Qt编程技巧



Qt编程有什么技巧?以命令行的形式改变窗口的现实风格
./xxx -style cde/motif/plastique

根据标签快捷键定位输入框
QLabel *label = new QLabel(tr(“&New”));
QLineEdit *edit = new QLineEdit();
label->setBubby(edit);

默认按钮:当用户按下Enter的时候,能够按下对应的按钮
button->setDefault(true);

禁止按钮:显示为灰色,不和用户交互
button->setEnabled(false);

布局中占用其他的剩余空间
layout->addStretch();

设置窗口的固定高度和宽度
dlg->setFixedHeight(dlg->sizeHint().height());
dlg->setFixedWidth(dlg->sizeHint().width());

信号与槽:
一个信号可以连接多个槽;
多个信号可以连接同一个槽;
一个信号可以与另一个信号连接;
连接可以被移除(disconnect);
信号的参数必须和槽的参数相匹配,参数个数可以多于槽的参数个数,
但多余的参数将被忽略。

利用Qt设计师生成窗口
生成文件dlg.ui;
继承Ui::Dlg.
//dlg.h
#include “ui_dlg.h”
class Dlg : public QDialog, public Ui::Dlg
{
Q_OBJECT
public:
Dlg(QWidget *parent = 0);

private slots:
void on_lineEdit_textChanged();
};

//dlg.cpp
#include “dlg.h”
Dlg::Dlg(QWidget *parent)
: QDialog(parent)
{
setupUi(this);

QRegExp regExp(“[A-Za-z][1-9][0-9]{0,2}”);
lineEdit->setValidator(new QRegExpValidator(regExp, this));

}

void Dlg::on_lineEdit_textChanged()
{
okBtn->setEnabled(lineEdit->hasAcceptableInput());
}


自动连接信号与槽
setupUi函数会自动将符合on_objectName_signalName()命名惯例的任意槽
与相应的objectName的signalName()信号连接到一起。上例中,建立了下面
的信号-槽关系:
connect(lineEdit, SIGNAL(textChanged(const QString &)),
this, SLOT(on_lineEdit_textChanged()));

删除父对象时,它的子对象会被自动删除

通过布局管理器来管理扩展对话框的窗口大小
layout()->setSizeConstraint(QLayout::SetFixedSize);

设计一个可扩展对话框的基本思路:
切换按钮;
信号-槽连接;
不可以改变尺寸大小的布局。

多页窗口部件有:QTabWidget, QToolBox

项目视图窗口部件(带滚动条):QListView, QTreeView, QTableView

为应用程序提供图片的方法:
把图片保存在文件中,并且在运行时载入它们;
把XPM文件包含在源代码中;
使用Qt的资源管理机制。

使用资源管理机制的方法:
1.将图片放在images/目录下;
2.在xxx.pro加入:RESOURCES = xxx.qrc
3.增加资源文件xxx.qrc, 内容形式如下:

images/icon.png

images/abc.png

4.源代码中引用方式:setWindowIcon(QIcon(“:/images/icon.png”));
或者 setWindowIcon(QIcon(“:/title.png”));

创建菜单栏、工具栏、状态栏
void MainWin::createActions()
{
newAct = QAction(tr(“&New”), this); // 加速键N
newAct->setIcon(QIcon(“images/new.png”)); // 图标
newAct->setShortcut(QKeySequence::New);  // 快捷键 Ctrl+N
// newAct->setShortcut(“Ctrl+N”);  // 快捷键 Ctrl+N
newAct->setStatusTip(tr(“Create a new file”)); // 状态提示
connect(newAct, SIGNAL(triggered()), this, newFile());

showGridAct->setCheckable(true); // 带复选框的菜单
showGridAct->setChecked(true);   // 选中

}
// 菜单栏
void MainWin::createMenus()
{
fileMenu = menuBar()->addMenu(tr(“&File”)); // file菜单
fileMenu->addAction(newAct); // 添加到菜单中

//QAction *separatorAct;
fileMenu->addSeparator(); // 添加间隔器

editMenu = menuBar()->addMenu(tr(“&Edit”)); // edit菜单
QMenu *subMenu = editMenu->addMenu(tr(“&Select”)); // 添加子菜单
subMenu->addAction(…);

}
// 工具栏
void MainWin::createToolBars()
{
fileToolBar = addToolBar(tr(“&File”));
fileToolBar->addAction(newAct);

editToolBar = addToolBar(tr(“&Edit”));
editToolBar = addAction(…);
editToolBar = addSeparator();

}
// 状态栏
void MainWin::createStatusBar()
{
locationLabel = new QLabel(tr(” W999 “));
locationLabel->setAlignment(Qt::AlignHCenter);
locationLabel->setMinimumSize(locationLabel->sizeHint());


otherLabel = new QLabel;
otherLabel->setIndent(3); // 缩进3个字符

statusBar()->addWidget(locationLabel);
statusBar()->addWidget(otherLabel, 1); // 窗口改变时,伸展它
}

模态对话框与非模态对话框
模态对话框典型例子:打开文件对话框,警告对话框
非模态对话框典型例子:查找对话框
模态对话框一般在堆中创建,非模态对话框一般在栈中创建
模态对话框使用exec()显示,非模态对话框使用show()显示
void MainWin::find()
{
if (!findDlg) // 不存在,创建它
{
findDlg = new FindDlg(this);
}
findDlg->show(); // 显示,并且是非模态的
findDlg->raise(); // 位于最上方
findDlg->activateWindow(); // 激活
}
void MainWin::goTo()
{
GoToDlg dlg(this);
if (dlg.exec()) // 模态的
{
// 对话框返回true(QDialog::Accepted)

}
// 函数结束时,自动销毁对话框
}

创建一个启动画面
int main(…)
{
QApplication app(…);
QSplashScreen *splash = new QSplashScreen;
splash->setPixmap(QPixmap(“:/images/splash.png”));
splash->show();
app.processEvents(); // 处理点击启动画面的事件
splash->showMessage(QObject::tr(“XXXX YYYYY …”),
Qt::AlignRight|Qt::AlignTop, Qt::white);
MainWin win;
splash->showMessage(…);
initNetwork(…);

win.show();
splash->finish(&win);
delete splash;

return app.exec();
}

MainWindow的中央窗口部件可以为:
一个标准的Qt窗口部件;
一个自定义的窗口部件;
一个带布局管理器的普通QWidget;
一个切分窗口(QSplitter);
一个多文档工作空间(QMdiArea)。

读写平台无关的二进制文件
bool writeFile(QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly))
{
QMessageBox::warning(this, tr(“”), tr(“Can not write file %1:\n%2″)
.arg(file.fileName()).arg(file.errorString()));
return false;
}
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_6);
out << quint32(0X11223344);
QApplication::setOverrideCursor(Qt::WaitCursor);
out << quint8(x) << qint32(y) << QString(str);
out << …

QApplication::restoreOverrideCursor();
return true;
}
bool readFile(QString &fileName)
{
QFile file(fileName);
if (!file.open(QIODevice::ReadOnly))
{
QMessageBox::warning(this, tr(“”), tr(“Can not read file %1:\n%2″)
.arg(file.fileName()).arg(file.errorString()));
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_6);

quint32 magic;
in >> magic;
if (magic != 0×11223344)
{
QMessageBox::warning(this, tr(“”), tr(“The file is not a xxx file.”));
return false;
}
QApplication::setOverrideCursor(Qt::WaitCursor);
quint8 x;
qint32 y;
QString str;
while (!in.end())
{
in >> x >> y >> str;
in >> …

}
QApplication::restoreOverrideCursor();
return true;
}

创建一个自定义窗口部件的过程:
选择一个合适的窗口部件;
对它子类化;
实现虚函数,改变它的行为。

构建一个可以集成到Qt设计师中的窗口部件
// iconeditor.h
#ifndef ICONEDITOR_H
#define ICONEDITOR_H

#include
#include
#include

class IconEditor : public QWidget
{
Q_OBJECT // 必须
//设计师的属性编辑器显示这些自定义属性
Q_PROPERTY(QImage iconImage READ iconImage WRITE setIconImage)
Q_PROPERTY(int zoomFactor READ zoomFactor WRITE setZoomFactor)

public:
IconEditor(QWidget *parent = 0);
void setIconImage(const QImage &image);
QImage iconImage() const { return image; }
void setZoomFactor(int zoom);
int zoomFactor() const { return zoom; }
QSize sizeHint() const; // 窗口的理性尺寸

protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event); // 必须

private:
QImage image;
int zoom;
};

#endif

IconEditor::IconEditor(QWidget *parent)
: QWidget(parent)
{
setAttribute(Qt::WA_StaticContents);
// 告诉布局管理器,理想尺寸是它的最小尺寸,不能对它缩小!
setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
zoom = 8; // 一个像素将显示成一个8×8的正方形
image = QImage(16, 16, QImage::Format_ARGB32); // 16×16像素的图片
image.fill(qRgba(0, 0, 0, 0)); // 黑色,完全透明
}
void IconEditor::sizeHint() const
{
QSize size = zoom * image.size();
if (zoom >=3)
size += QSize(1, 1);
return size;
}
void IconEditor::setIconImage(const QImage &img)
{
if (img != image)
{
image = img.convertToFormat(QImage::Format_ARGB32);
update(); // 重绘窗口
updateGeometry(); // 告诉布局管理器,理想尺寸已经发生改变,布局需要调整
}
}
自动调用的情况:
窗口第一次显示;
大小改变;
被遮挡,然后再次显示。

主动调用的情况:
update();
repaint(); // 不常用
void IconEditor::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setPen(palette().forground().color()); // 调色板
painter.drawLine(…);
}
void IconEditor::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
setImagePixel(event->pos(), true);

}
else if (event->button() == Qt::LeftButton)
{
setImagePixel(event->pos(), false);

}
}
窗口属性Qt::WA_StaticContents
当重新改变窗口部件的大小时,窗口部件的内容并没有发生改变,
而且内容仍旧保留从窗口左上角开始的特性。这样就可以避免重绘
已经显示的区域。

在设计师中集成自定义窗口部件的2种方法
提升法:拖动一个自定义窗口的父窗口对象,右键->提示为…
插件法:创建一个插件库

当应用程序的最后一个窗口关闭时,程序退出
在main中使用下面语句:
QObject::connect( qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()) );

键盘:
Qt::Key_Plus: 对数字小键盘起作用,对于大键盘,要同时按下Shift
Qt::Key_Enter: 对数字小键盘起作用

当定义一个函数时,如果不没有用到其中的参数p,但又不想在编译时,产生警告:
在函数的开头,使用宏
Q_UNUSED(p);

在QGraphicsItem的paint函数中,如果不希望线的宽度缩放,则
painter->setPen(color); //不指定pen的宽度,或者指定为0.