<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                #(11):布局管理器 所謂 GUI 界面,歸根結底,就是一堆組件的疊加。我們創建一個窗口,把按鈕放上面,把圖標放上面,這樣就成了一個界面。在放置時,組件的位置尤其重要。我們必須要指定組件放在哪里,以便窗口能夠按照我們需要的方式進行渲染。這就涉及到組件定位的機制。Qt 提供了兩種組件定位機制:絕對定位和布局定位。 顧名思義,絕對定位就是一種最原始的定位方法:給出這個組件的坐標和長寬值。這樣,Qt 就知道該把組件放在哪里以及如何設置組件的大小。但是這樣做帶來的一個問題是,如果用戶改變了窗口大小,比如點擊最大化按鈕或者使用鼠標拖動窗口邊緣,采用絕對定位的組件是不會有任何響應的。這也很自然,因為你并沒有告訴 Qt,在窗口變化時,組件是否要更新自己以及如何更新。如果你需要讓組件自動更新——這是很常見的需求,比如在最大化時,Word 總會把稿紙區放大,把工具欄拉長——就要自己編寫相應的函數來響應這些變化。或者,還有更簡單的方法:禁止用戶改變窗口大小。但這總不是長遠之計。 針對這種變化的需求,Qt 提供了另外的一種機制——布局——來解決這個問題。你只要把組件放入某一種布局,布局由專門的布局管理器進行管理。當需要調整大小或者位置的時候,Qt 使用對應的布局管理器進行調整。下面來看一個例子: ~~~ // !!! Qt 5 int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.setWindowTitle("Enter your age"); QSpinBox *spinBox = new QSpinBox(&window); QSlider *slider = new QSlider(Qt::Horizontal, &window); spinBox->setRange(0, 130); slider->setRange(0, 130); QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue); void (QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged; QObject::connect(spinBox, spinBoxSignal, slider, &QSlider::setValue); spinBox->setValue(35); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(spinBox); layout->addWidget(slider); window.setLayout(layout); window.show(); return app.exec(); } ~~~ 這段例子還是有些東西值得解釋的。我們可以先來看看運行結果: [![](https://box.kancloud.cn/2015-12-29_568232455c2d2.png)](http://files.devbean.net/images/2012/09/layout-demo.png) 當我們拖動窗口時,可以看到組件自動有了變化: [![](https://box.kancloud.cn/2015-12-29_568232456c586.png)](http://files.devbean.net/images/2012/09/layout-demo-2.png) 我們在這段代碼中引入了兩個新的組件:`QSpinBox`和`QSlider`。`QSpinBox`就是只能輸入數字的輸入框,并且帶有上下箭頭的步進按鈕。`QSlider`則是帶有滑塊的滑竿。我們可以從上面的截圖中清楚地辨別出這兩個組件。當我們創建了這兩個組件的實例之后,我們使用`setRange()`函數設置其范圍。既然我們的窗口標題是“Enter your age(輸入你的年齡)”,那么把 range(范圍)設置為 0 到 130 應該足夠了。 有趣的部分在下面的`connect()`函數。我們已經清楚`connect()`函數的使用,因此我們寫出 ~~~ QObject::connect(slider, &QSlider::valueChanged, spinBox, &QSpinBox::setValue); ~~~ 將 slider 的`valueChanged()`信號同 spinBox 的`setValue()`函數相連。這是我們熟悉的。但是,當我們直接寫 ~~~ QObject::connect(spinBox, &QSpinBox::valueChanged, slider, &QSlider::setValue); ~~~ 的時候,編譯器卻會報錯: ~~~ no matching function for call to 'QObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int)) ~~~ 這是怎么回事呢?從出錯信息可以看出,編譯器認為`QSpinBox::valueChanged`是一個 overloaded 的函數。我們看一下`QSpinBox`的文檔發現,`QSpinBox`的確有兩個信號: * void valueChanged(int) * void valueChanged(const QString &) 當我們使用`&QSpinBox::valueChanged`取函數指針時,編譯器不知道應該取哪一個函數(記住前面我們介紹過的,經過 moc 預處理后,signal 也是一個普通的函數。)的地址,因此報錯。解決的方法很簡單,編譯器不是不能確定哪一個函數嗎?那么我們就顯式指定一個函數。方法就是,我們創建一個函數指針,這個函數指針參數指定為 int: ~~~ void (QSpinBox:: *spinBoxSignal)(int) = &QSpinBox::valueChanged; ~~~ 然后我們將這個函數指針作為 signal,與 QSlider 的函數連接: ~~~ QObject::connect(spinBox, spinBoxSignal, slider, &QSlider::setValue); ~~~ 這樣便避免了編譯錯誤。 仔細觀察這兩個`connect()`的作用,它們實際完成了一個雙向的數據綁定。當然,對于 Qt 自己的信號函數,我們可以比較放心地使用。但是,如果是我們自己的信號,應當注意避免發生無限循環! 下面的代碼,我們創建了一個`QHBoxLayout`對象。顯然,這就是一個布局管理器。然后將這兩個組件都添加到這個布局管理器,并且把該布局管理器設置為窗口的布局管理器。這些代碼看起來都是順理成章的,應該很容易明白。并且,布局管理器很聰明地做出了正確的行為:保持`QSpinBox`寬度不變,自動拉伸`QSlider`的寬度。 Qt 提供了幾種布局管理器供我們選擇: * `QHBoxLayout`:按照水平方向從左到右布局; * `QVBoxLayout`:按照豎直方向從上到下布局; * `QGridLayout`:在一個網格中進行布局,類似于 HTML 的 table; * `QFormLayout`:按照表格布局,每一行前面是一段文本,文本后面跟隨一個組件(通常是輸入框),類似 HTML 的 form; * `QStackedLayout`:層疊的布局,允許我們將幾個組件按照 Z 軸方向堆疊,可以形成向導那種一頁一頁的效果。 當然,我們也可以使用 Qt 4 來編譯上面的代碼,不過,正如大家應該想到的一樣,我們必須把`connect()`函數修改一下: ~~~ // !!! Qt 4 int main(int argc, char *argv[]) { QApplication app(argc, argv); QWidget window; window.setWindowTitle("Enter your age"); QSpinBox *spinBox = new QSpinBox(&window); QSlider *slider = new QSlider(Qt::Horizontal, &window); spinBox->setRange(0, 130); slider->setRange(0, 130); QObject::connect(slider, SIGNAL(valueChanged(int)), spinBox, SLOT(setValue(int))); QObject::connect(spinBox, SIGNAL(valueChanged(int)), slider, SLOT(setValue(int))); spinBox->setValue(35); QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(spinBox); layout->addWidget(slider); window.setLayout(layout); window.show(); return app.exec(); } ~~~ 這里我們強調一下,上面的代碼在 Qt 5 中同樣可以編譯通過。不過,我們減少了使用函數指針指定信號的步驟。也就是說,在 Qt 5 中,如果你想使用 overloaded 的 signal,有兩種方式可供選擇: 1. 使用 Qt 4 的`SIGNAL`和`SLOT`宏,因為這兩個宏已經指定了參數信息,所以不存在這個問題; 2. 使用函數指針顯式指定使用哪一個信號。 有時候,使用 Qt 4 的語法更簡潔。但是需要注意的是,Qt 4 的語法是沒有編譯期錯誤檢查的。這也是同 Qt 5 的信號槽新語法不同之處之一。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看