Qt 介面設計總結
把工作中學到的技巧記錄下來:
1. 子窗體或控制元件,重寫paintEvent事件,畫邊框、背景、文字、圖片效果比較好。用paintEvent 事件畫邊框,用QPalette設定背景。
// 畫邊框
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor(225,70,56), 2));
// painter.setBrush(QColor(16,62,81)); // 也可設定背景,有時效果不好
painter.drawRoundedRect(rect(), 5.0, 5.0);
// 設定背景
QPalette pal = palette();
pal.setBrush(QPalette::Window, QColor(16,62,81));
setPalette(pal);
setAutoFillBackground(true);
2. 繼承QDialog,想讓對話方塊以模態執行,使用exec(),繼承時使用setWindowFlags()後則達不到模態的效果。不知道原因。
3. QStringList 輸出
QStringList m_strLang << "English"
<< "Chinese";
qDebug("set language: %s", m_strLang.at(0).toLocal8Bit().constData());
4. QStringList 使用注意
QStringList strDateformatList;
strDateformatList
<< m_strMonth + "-" + m_strDay + "-" + m_strYear
<< m_strDay + "-" + m_strMonth + "-" + m_strYear
<< m_strYear + "-" + m_strMonth + "-" + m_strDay
;
如果strDateformatList 在生命週期內多次呼叫,則會多次插入字串,使得字串重複,這不是我們想要的。那就定義為區域性變數,每次會重新賦值,達到更新的目的。
5.需要動態重新的頁面可以在showEvent函式中重新。
6. 用paintEvent或用調色盤為QWidget填充背景時,需要加上setAutoFillBackground(true);語句,否則沒效果。
7. 想使彈出的視窗為圓角,用paintEvent畫圓角矩形,但四個直角仍然存在,不美觀。可以把背景設為透明,用paintEvent畫出想要的背景,因為四個角沒有畫上背景,是透明的,所以看不見。
// 設定背景為透明 (建構函式中)
QPalette pal = palette();
pal.setBrush(QPalette::Window, QColor(255, 255, 255, 0));
setPalette(pal);
setAutoFillBackground(true);
// 畫背景和邊框 (paintEvent函式中)
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setPen(QPen(QColor(225,70,56), 2));
painter.setBrush(QColor(16,62,81));
painter.drawRoundedRect(rect(), 5.0, 5.0);
8. Qt::Key_Enter、Qt::Key_Reture
Qt::Key_Enter對應小鍵盤的Enter鍵
Qt::Key_Return對應大鍵盤的Enter鍵
9. 事件過濾。視窗部件的事件到達目的地之前提前獲取並處理相關事件,實現個性化的處理。
我在QLabel物件中放入兩個QPushButton物件和兩個QLabel物件,QPushButton實現值的調節,其中一個QLabel物件用於顯示值,一個QLabel物件用於顯示標題。類似SpinBox。在多個SpinBox上點選實現焦點切換,當滑鼠點到QPushButton上時,QPushButton處理了mousePressEvent事件,所以無法實現焦點切換。為兩個QPushButton物件安裝事件過濾器,然後在其父部件中處理eventFilter函式
m_btnLeft->installEventFilter(this);
m_btnRight->installEventFilter(this);
//安裝事件過濾器後,傳給m_btnLeft、m_btnRight的事件會首先發送給eventFilter函式
boolESpinBoxItem::eventFilter(QObject*obj,QEvent*ev)
{
if(obj==m_btnLeft||obj==m_btnRight)
{
if(ev->type()==QEvent::MouseButtonPress)
{
emitsign_spinBoxPressed(m_nItem);
returntrue; // 不傳給目標物件處理
}
}
returnfalse; // 不處理的事件則傳給目標物件處理
}
10. 拍照動畫
使用QTimeLine和QGraphicsPixmapItem物件,當時間線幀改變時,設定QGraphicsPixmapItem的位置,實現動畫效果。
// 在QGraphicsView建構函式中
// take photo animation
m_timerAnimation = new QTimeLine(900);
m_timerAnimation->setCurveShape(QTimeLine::LinearCurve);
m_timerAnimation->setFrameRange(0, 240);
m_pixmapUpAnimation = QPixmap(":/images/animation.png");
m_pixmapDownAnimation = QPixmap(":/images/animation.png");
m_upPixmapItem = new QGraphicsPixmapItem;
m_downPixmapItem = new QGraphicsPixmapItem;
m_upPixmapItem->setZValue(4);
m_downPixmapItem->setZValue(4);
m_upPixmapItem->setPos(0, 0); // 左上角為原點
m_downPixmapItem->setPos(0, 240);
scene()->addItem(m_upPixmapItem);
scene()->addItem(m_downPixmapItem);
m_upPixmapItem->hide();
m_downPixmapItem->hide();
connect(m_timerAnimation, SIGNAL(frameChanged(int)), this, SLOT(slot_playAnimation(int)));
// 槽函式
void EGraphicsView::slot_playAnimation(int nFrame)
{
m_upPixmapItem->show();
m_downPixmapItem->show();
qDebug("nFrame: %d", nFrame);
if(nFrame < 120)
{
m_upPixmapItem->setPixmap(m_pixmapUpAnimation.scaled(320, nFrame));
m_downPixmapItem->setPixmap(m_pixmapDownAnimation.scaled(320, nFrame));
m_downPixmapItem->setPos(0, 240 - nFrame);
}
else
{
m_upPixmapItem->setPixmap(m_pixmapUpAnimation.scaled(320, 240 - nFrame));
m_downPixmapItem->setPixmap(m_pixmapDownAnimation.scaled(320, 240 - nFrame));
m_downPixmapItem->setPos(0, nFrame);
}
}
11.在移動裝置上使用漸變或使用漸變的圖片時,會出現條紋狀,達不到效果。在初始化QApplication對像前呼叫下面的語句則可以達到效果:
QApplication::setColorSpec(QApplication::ManyColor); //the right choice for applications that use thousands of colors
QApplication app(argc, argv, QApplication::GuiServer );
12.用setStyleSheet設定背景圖片
m_labelButton->setStyleSheet("background-image: url(:images/shutdown/slider.png); background-repeat: no-repeat;"); //注意,不加background-repeat: no-repeat可能會出現透視,很醜。QLabel物件可用setPixmap設定象素圖。
13.使對話方塊圓角
//建構函式中
setAutoFillBackground(true);
QPalette pal = palette();
pal.setColor(QPalette::Window, QColor(0, 0, 0, 0));
setPalette(pal);
//paintEvent函式中
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.setPen(QPen(Qt::red,2));
painter.setBrush(QColor(16,62,81));
painter.drawRoundedRect(rect(),5.0,5.0);
// 圓角處有雜色,原因不祥
14. 對某些預設事件的處理修改
正常情況下,按下Tab鍵,被QWidget看成是去移動鍵盤焦點,但少數視窗部件需要自行解釋。
bool MyClass::event(QEvent *e)
{
if(e->type() == QEvent::KeyPress)
{
QKeyEvent *ke = (QKeyEvent *)e;
if(ke->key() == Qt::Key_Tab)
{
//這裡是特定的Tab處理
k->accept();
return TRUE;
}
}
else if(e->type() >= QEvent::User)
{
// 這裡是自定義事件處理
return TRUE;
}
QWidget::event(e);
}
15.QLabel繼承QFrame,有QFrame的特性。如setFrameStyle(int)可設定QLabel的FrameStyle(框架型別)
FrameStyle有兩種:
a.第一種是frameshape:
有以下幾種型別:
Constant | Value | Description |
---|---|---|
QFrame::NoFrame | 0 | QFramedraws nothing |
QFrame::Box | 0x0001 | QFramedraws a box around its contents |
QFrame::Panel | 0x0002 | QFramedraws a panel to make the contents appear raised or sunken |
QFrame::StyledPanel | 0x0006 | draws a rectangular panel with a look that depends on the current GUI style. It can be raised or sunken. |
QFrame::HLine | 0x0004 | QFramedraws a horizontal line that frames nothing (useful as separator) |
QFrame::VLine | 0x0005 | QFramedraws a vertical line that frames nothing (useful as separator) |
QFrame::WinPanel | 0x0003 | draws a rectangular panel that can be raised or sunken like those in Windows 95. Specifying this shape sets the line width to 2 pixels. WinPanel is provided for compatibility. For GUI style independence we recommend using StyledPanel instead. |
b.第二種是frameshadow
有以下幾種型別:
Constant | Value | Description |
---|---|---|
QFrame::Plain | 0x0010 | the frame and contents appear level with the surroundings; draws using the paletteQPalette::WindowTextcolor (without any 3D effect) |
QFrame::Raised | 0x0020 | the frame and contents appear raised; draws a 3D raised line using the light and dark colors of the current color group |
QFrame::Sunken | 0x0030 | the frame and contents appear sunken; draws a 3D sunken line using the light and dark colors of the current color group |
組合值的效果圖:
15.幾種位置資訊
x()、y()、pos()函式都是獲得整個窗體左上角的座標位置。需frameGeometry與geometry相對應,frameGemometry()是獲得整個窗體的左上頂點和長、寬值,需geometry()函式獲得的是窗體內中央域的左上頂點座標以及長、寬值。直接呼叫width()和height()函式獲得的是中央區域的長和寬的值。還有兩個函式rect()、size(),呼叫它們獲得的結果也都是對於窗體的中央區域而言的。size()獲得的是窗體中央區域的長、寬值,rect()與geometry()一樣返回一個QRect物件。其中,兩個函式獲得的長寬、值是一樣的,都是窗體中央區域的長、寬值,只是左上頂點的座標值不一樣,geometry()獲得的左上角頂點座標是相對於父窗體而言的座標,,而rect()獲得的左上角頂點座標始終為(0, 0)。
效果圖:
窗體在左上角時:
16.幾種輸入對話方塊。
a.獲取文字對話方塊
QString strName=QInputDialog::getText(this,tr("User Name"),tr("Please Input New Name:"),QLineEdit::Normal,m_labelName->text(),&ok);
b.獲取項對話方塊
QStringList list;
list<<tr("男")<<tr("女");
QStringstrSex=QInputDialog::getItem(this,tr("User Sex"),tr("Please Select Sex:"),list,0,false,&ok);
c.獲取整數對話方塊
boolok;
int nAge = QInputDialog::getInteger(this, tr("User Age"), tr("Please Input Age:"), m_labelAge->text().toInt(), 18, 30, 1, &ok);
if(ok)
{
m_labelAge->setText(QString(tr("%1").arg(nAge)));
}
d.獲得雙精度對話方塊
boolok;
doublenHeight=QInputDialog::getDouble(this,tr("User Height"),tr("Please Input Height:"),m_labelHeight->text().toDouble(),160.5,270.5,1,&ok);
if(ok)
{
m_labelHeight->setText(QString(tr("%1").arg(nHeight)));
}
17.自定義QMessageBox
QMessageBox customMsgBox;
customMsgBox.setWindowTitle("Custom message box");
QPushButton*lockButton=customMsgBox.addButton(tr("Lock"),QMessageBox::ActionRole);
QPushButton*unlockButton=customMsgBox.addButton(tr("Unlock"),QMessageBox::ActionRole);
QPushButton*cancelButton=customMsgBox.addButton(QMessageBox::Cancel);
customMsgBox.setIconPixmap(QPixmap(":/images/1.png"));
customMsgBox.setText(tr("This is a custom message box"));
customMsgBox.exec();
if(customMsgBox.clickedButton()==lockButton)
{
m_labelMessage->setText("Custom MessageBox button / lock");
}
elseif(customMsgBox.clickedButton()==unlockButton)
{
m_labelMessage->setText("Custom MessageBox button / unlock");
}
elseif(customMsgBox.clickedButton()==cancelButton)
{
m_labelMessage->setText("Custom MessageBox button / Cancel");
}
效果圖:
定義好的MessageBox
QMessageBox::question
QMessageBox::information
QMessageBox::warning
QMessageBox::critical
QMessageBox::about
QMessageBox::aboutQt
18.在編寫程式時,初始化窗體時最好不要使用setGeometry()函式,而用resize()和move()函式代替,因為使用setGeometry()會導致窗體show()之後在錯誤 的位置上停留很短暫的一段時間,帶來閃爍現象。
19.提示錯誤:E:\vm_shared\study\graphicsview\debug\moc_navibar.cpp:39: error: `staticMetaObject' is not a member of `QGraphicsRectItem'
錯誤原因:因為QGraphicsRectItem不是QObject的子類,所以在類的宣告中不能有Q_OBJECT巨集、signal和slot。
20.抓圖功能:
// 使用Qt自帶的靜態函式grabWindow,指定窗體ID,抓圖的起啟位置和麵積大小。
QImage image = QPixmap::grabWindow(QApplication::desktop()->winId(), 0, 0, nDesktopWidth, nDesktopHeight).toImage().scaled(640, 480);
21.檢視去掉滾動條
view->setFrameShape(QFrame::NoFrame);
通過佈局指定檢視的父窗體時,使用上面程式碼去不掉滾動條。而需要使用view = new QGraphicsView(this);指定父窗體。
最好辦法是: view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 一直關掉滾動條
22.QpushButton圓角
QPushButton { border: 2px solid #8f8f91; border-radius: 6px; background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #f6f7fa, stop: 1 #dadbde); min-width: 80px; }
note: 當QPushButton無邊框(border: 0px;),有設定背景顏色(background-color: rgb(6,43,58);)時,設定圓角會出現鋸齒,因為圓角是邊框為圓角,邊框大小不能為0px.想讓按鈕只顯示一種顏色(看不見邊框顏色),則把邊框顏色設為背景色即可。如圖: