2011年10月23日 星期日

Qt - 依QLineEdit的內容自動調整整個視窗的大小

Qt - 選擇資料夾或特定的檔案的例子中,當使用者選擇檔案或資料夾後,會將其完整路徑放到QLineEdit裡面~
但是,若路徑過長,並不會調整整個視窗的大小,讓使用都可以完整的看到其路徑。

若要調整其視窗大小,必需要調整Layout的相關關係~~

在Qt裡面,若有受到Layout的控制的話,裡面的元件的大小會受到以下兩個因素影響
1. Qt Layout的限制
QLayout::SetDefaultConstraint
最小尺吋設定為minimumSize ()
QLayout::SetFixedSize
視窗為sizeHint (),且不能被改變大小。
QLayout::SetMinimumSize
視窗被設定為minimumSize ()且不能被變的更小
QLayout::SetMaximumSize
視窗被設定為maximumSize ()且不能被變的更大
QLayout::SetMinAndMaxSize
最小尺吋為minimumSize ()、最大尺吋是maximumSize ()
QLayout::SetNoConstraint
不受到Layout的控制
2. 子視窗本身也受到自己的size policies及其最大/最小值的影響
QSizePolicy::Fixed
sizeHint () - sizeHint ()
QSizePolicy::Minimum
sizeHint () - 無限大
QSizePolicy::Maximum
0 - sizeHint ()
QSizePolicy::Preferred
0 - 無限大
QSizePolicy::Expanding
0 - 無限大
QSizePolicy::MinimumExpanding
sizeHint () - 無限大
QSizePolicy::Ignored
0 - 無限大

以下就是由Qt - 選擇資料夾或特定的檔案改的結果
main.cpp

#include <QApplication>
#include "MyWidget.h"

int main (
int argc,
char *argv[]
)
{
QApplication app (argc, argv);

MyWidget myWidget;

myWidget.show ();

return app.exec ();
}

MyWidget.h
#ifndef _MY_WIDGET_H_
#define _MY_WIDGET_H_

#include <QWidget>

class QLabel;
class QPushButton;
class QLineEdit;

class MyWidget : public QWidget {
Q_OBJECT

public:
MyWidget (QWidget *parent = 0);

private slots:
void browse ();
void ChangeSelectFile (bool);
void AdjustMainWindowSize (const QString &);

private:
QLabel *myLabel;
QPushButton *myPushButton;
QLineEdit *myLineEdit;
bool SelectFile;
};

#endif //#ifndef _MY_WIDGET_H_

MyWidget.cpp
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFileDialog>
#include <QGroupBox>
#include <QRadioButton>
#include <QSizePolicy>

#include "MyWidget.h"

MyWidget::MyWidget (QWidget *parent) : QWidget (parent) {
//
// init
//

myLabel = NULL;
myLineEdit = NULL;
myPushButton = NULL;

//
// Create Label component
//

myLabel = new QLabel (tr ("Target Name"), this);

//
// Create LineEdit component
//

myLineEdit = new QLineEdit (this);

//
// Set the width of QLineEdit from sizeHint () to max
//

myLineEdit->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);

//
// Create GroupBox and RadioButton component
//

QGroupBox *box = new QGroupBox (tr ("Select Type"));
QRadioButton *radio1 = new QRadioButton (tr ("File"));
QRadioButton *radio2 = new QRadioButton (tr ("Directory"));

//
// Set the default checked RadioButton for SelectFile
//

radio1->setChecked (true);
SelectFile = true;

//
// Set RadioButton into QHBoxLayout
// And set RadioButton into same GroupBox
//

QVBoxLayout *VLayout = new QVBoxLayout;
VLayout->addWidget (radio1);
VLayout->addWidget (radio2);
box->setLayout (VLayout);

//
// Create QPushButton component
//

myPushButton = new QPushButton (tr ("&Browse..."), this);

//
// Add all the components into QHBoxLayout
//

QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget (myLabel);
layout->addWidget (myLineEdit);
layout->addWidget (box);
layout->addWidget (myPushButton);

//
// Set main window to the sizeHint () and can not be changed
//

layout->setSizeConstraint (QLayout::SetFixedSize);
// layout->setSizeConstraint (QLayout::SetMinimumSize);

//
// Set the main Layout for MyWidget
//

this->setLayout (layout);

//
// Set the SIGNAL and SLOT for this component
//

connect (myPushButton, SIGNAL (clicked ()), SLOT (browse ()));
connect (radio1, SIGNAL (toggled (bool)), this, SLOT (ChangeSelectFile (bool)));

//
// When the content of QLineEdit changed, try to resize the Main Window
//

connect (myLineEdit, SIGNAL (textChanged (const QString &)), this, SLOT (AdjustMainWindowSize (const QString &)));
}

void MyWidget::browse () {

QString TargetItem;

QFileDialog myFileDialog (this);
if (SelectFile) {
TargetItem = myFileDialog.getOpenFileName (this, tr ("Open File"), QDir::currentPath (), tr ("All C++ files (*.cpp *.h)"));
} else {
TargetItem = myFileDialog.getExistingDirectory (this, tr ("Select Folder"), QDir::currentPath ());
}
if (TargetItem.isEmpty ()) {
// myLineEdit->setText (myFileDialog.directory ().absolutePath ());
// myLineEdit->clear ();
// do nothing
} else {
myLineEdit->setText (TargetItem);
}
}

void MyWidget::ChangeSelectFile (bool checked) {
SelectFile = checked;
}

void MyWidget::AdjustMainWindowSize (const QString & text) {
QFont myFont;
QFontMetrics fm (myFont);

//
// Calculate the width pixel by the number of word
//

myLineEdit->setMinimumWidth (fm.width (myLineEdit->text ()));

//
// Readjust the main window size by new MinimumWidth
//

// resize (sizeHint ());
}


這裡有一些部分要特別注意~
myLineEdit->setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::Fixed);

設定QLineEdit自身的尺寸策略(size policies)
寬度是sizeHint () ~ 無窮大
高度是限制在sizeHint ()

layout->setSizeConstraint (QLayout::SetFixedSize);

設定主視窗的Layout的長寬為sizeHint (),且不能被改變~

myLineEdit->setMinimumWidth (fm.width (myLineEdit->text ()));

這裡是根據QLineEdit所輸入的內容來決定QLineEdit的最小寬度是多少,
另外,要注意的是,用text ().size ()是回傳有幾個字元,但是,setMinimumWidth是要輸入要幾個pixel,因此,必需由目前使用的字型來決定幾個字元需要多少個pixel。

本程式會把使用者輸入的字串長度轉成pixel,並且設定為QLineEdit的最小長度。
當最小長度大於原本的sizeHint的時候,sizeHint就會被重新設定為MinimumWidth的寬度。
而layout則是根據sizeHint來調整MyWidget的小大~

因此,QLineEdit的寬度會保持在
QLineEdit::sizeHint() ~ fm.width (myLineEdit->text ())

在還沒有輸入任何資料前的樣子


在選擇完檔案或資料夾時,主視窗會自動變大~


在經過這個sample code後,若某一個元件是有被Layout來管理的話,要調整他的大小,沒有辦法直接設定他的大小,必需
1. 設定Layout的policy
2. 設定Widget本身的policy,其最大、最小的寬度
那麼Qt layout manager就可以跟據這一些資料來調整Widget最適合的大小。

參考資料:
QFontMetrics Class Reference
Measuring text width in Qt
QBoxLayout與QWidget之間的關係

沒有留言: