Qt开发思路库

1.概述

此篇文章主要用来记录自己在使用Qt框架开发应用的过程中遇到的问题及解决方法(需求及实现方式),同时也会记录一些开发心得,持续记载中…

2.问题及解决方法

  1. 问题: 无法使用使用属性样式选择器([enabled]=“false”)在样式中设置控件不可用时的样式。

解决方法:使用控件 :disabled 伪状态设置不可用时的样式。

  1. 问题: 直接使用css中的渐变色样式来设置控件背景渐变色没有效果。

解决方法:由qss与css的区别导致的,直接先在QtDesigner中添加渐变色(QtDesigner会自动生成渐变色的样式),然后修改需要用到的目标颜色即可。

  1. 问题: QMessageBox中按钮文字语言为英文。

解决方法:主要方法是加载翻译对象,解决过程如下,最后展示如何加载翻译对象。
①先将Qt安装目录下的中文翻译文件(qt_zh_CN.qm)拷贝到工程目录下(翻译文件源路径为:“F:\Software\Qt\5.15.2\msvc2019_64\translations\qt_zh_CN.qm”,其中前面部分为Qt的安装路径)
②调用QApplication对象的installTranslator(QTranslator* translator)加载翻译对象。
③此时如果弹窗还是英文的话,表示上面的翻译文件没有包含QMessageBox弹窗部分,则需要将另外一个翻译文件(qtbase_zh_CN.qm)也加载进来(文件路径为:https://github.com/doufu3344/qtbase_zh)。

int main(int argc,char* argv[]){
	QApplication application(argc,argv);
	//加载qt_zh_CN.qm
	QTranslator qtTranslator;
  	qtTranslator.load(":/language/qt_zh_CN.qm");
  	application.installTranslator(&qtTranslator);
  	
	//如果上面代码未能解决问题,则需要追加下面部分,加载qtbase_zh_CN.qm
  	QTranslator qtbaseTranslator;
  	qtbaseTranslator.load(":/language/qtbase_zh_CN.qm");
  	application.installTranslator(&qtbaseTranslator);
}

3.开发手册

3.1控件样式定义

将控件样式统一记录在 .qss 文件中,然后在应用程序初始化时读取该文件内容并赋值给qApp对象,完成样式初始化。这样做的好处是:避免了在许多处代码中定义各种样式字符串,方便统一管控。然而,在窗口设计时,允许在QtDesigner中定义各个控件的样式,因为这样方便及时查看效果,提高设计效率。因此,.qss文件适合记录一些公共子控件的样式,比如菜单样式、滚动条样式等。(使用vscode打开.qss文件,会有语法高亮的效果,比在QtCreator里面编辑方便得多)。

3.2qss语法(选择器、子控件、伪状态)

表格来源为Qt QSS选择器简介,Qss语法文档为The Style Sheet Syntax,Qss参考手册为Qt Style Sheets Reference
1. 选择器

选择器示例说明
通用选择器*匹配所有部件
类型选择器QPushButton匹配QPushButton及其子类的实例
属性选择器QPushButton[flat=“false”]匹配所有属性flat属性为false的对象
类选择器.QPushButton匹配QPushButton实例,不包含子类
ID选择器QPushButton#btnOk匹配对象名为btnOk的对象
子选择器QDialog>QPushButton匹配作为QDialog的直接子级的QPushButton实例
后代选择器QDialob QPushButton匹配作为QDialog的后代(子、孙等)的QPushButton实例

2. 子控件

代码说明
QComboBox QAbstractItemView::item设置QComboBox下拉框子项样式
QScrollBar::handle设置滚动条滑块样式

3. 伪状态

代码说明
QPushButton:hover设置QPushButton鼠标悬浮状态下的样式
QPushButton:disabled设置QPushButton不可用状态下的样式

3.3设计QToolButton不同状态图标及样式

方式1:使用qss中的background属性设置控件不同状态下的样式。
方式2:使用监听器,通过调用按钮的installEventFilter函数,将按钮的事件委托给其他窗口(一般是父窗口)监听,其他窗口在eventFilter函数中处理QEvent:Enter与QEvent:Leave两个事件来处理按钮图标及样式。

/*方式1*/
 QToolButton { background:url(:/image/ui/uires/normal.png) no-repeat center center; }
 QToolButton:hover { background:url(:/image/ui/uires/hover.png) no-repeat center center;}
/*方式2*/
/** 
* @brief 添加按钮函数
*/
void ExampelWidget::AddButton(const QString& text,const QIcon& icon){
	QToolButton* button = new QToolButton(this);
	button->setText(text);
	button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
	button->setIcon(icon);
	button->setIconSize(QSize(27, 27));
	button->installEventFilter(this);//委托给当前对象处理按钮的事件
}
/** 
* @brief 重写QWidget的事件处理函数
*/
bool ExampleWidget::eventFilter(QObject *watched, QEvent *event){
	QToolButton *button = qobject_cast<QToolButton *>(watched);
	if (button != nullptr) {
	  if (event->type() == QEvent::Enter) {
	    button->setIcon(m_icons[button].pixmap(button->iconSize(), QIcon::Active));
	  } else if (event->type() == QEvent::Leave) {
	    button->setIcon(m_icons[button].pixmap(button->iconSize(), QIcon::Normal));
	  }
	}
	return QWidget::eventFilter(watched, event);
}

3.4设计QTableWidget表头居中自动换行

table->horizontalHeader()>setDefaultAlignment(Qt::AlignCenter | (Qt::Alignment)Qt::TextWordWrap);

3.5操作Excel表格文件

使用开源库QtXlsxWriter。下面写明如何在项目中配置使用QtXlsxWriter。(需要更详细说明的可以参照文章QtXlsx使用方法(强大的Excel))。

  1. 克隆QtXlsxWriter项目到本地,进行编译,版本要与主项目一致。
  2. 拷贝编译后的include文件夹到本地Qt安装目录下的include目录。(如:D:\3rdCode\QtXlsxWriter\QtXlsxWriter-master\build-qtxlsx-Desktop_Qt_5_15_2_MSVC2019_32bit-Debug\include\QtXlsx ⇒ F:\Software\Qt\5.15.2\msvc2019\include)
  3. 拷贝编译后的lib文件夹下面的 ** Qt5Xlsxd.lib Qt5Xlsx.lib Qt5Xlsx.prl Qt5Xlsxd.prl ** 4个文件到本地Qt安装目录下的lib目录。(如:D:\3rdCode\QtXlsxWriter\QtXlsxWriter-master\build-qtxlsx-Desktop_Qt_5_15_2_MSVC2019_32bit-Debug\lib ⇒ F:\Software\Qt\5.15.2\msvc2019\lib)。
  4. 拷贝编译后的lib文件夹下面的 ** Qt5Xlsx.dll Qt5Xlsxd.dll ** 2个文件到本地Qt安装目录下的bin目录。(如:D:\3rdCode\QtXlsxWriter\QtXlsxWriter-master\build-qtxlsx-Desktop_Qt_5_15_2_MSVC2019_32bit-Debug\lib ⇒ F:\Software\Qt\5.15.2\msvc2019\bin)
  5. 拷贝编译后的mkspecs\modules文件夹下面的 qt_lib_xlsx.pri 1个文件到本地Qt安装目录下的mkspecs\modules目录。(如D:\3rdCode\QtXlsxWriter\QtXlsxWriter-master\build-qtxlsx-Desktop_Qt_5_15_2_MSVC2019_32bit-Debug\mkspecs\modules ⇒ F:\Software\Qt\5.15.2\msvc2019\mkspecs\modules)
  6. 如果项目使用qmake编译,则直接在.pro文件里面加入QT+=xlsx,则可以使用了该库了。
  7. 如果项目使用cmake编译,则需要先拷贝编译后的lib/cmake/Qt5Xlsx文件夹到本地Qt安装目录下的lib/cmake目录下,再在CMakeLists文件中引入该库。(如:D:\3rdCode\QtXlsxWriter\QtXlsxWriter-master\build-qtxlsx-Desktop_Qt_5_15_2_MSVC2019_32bit-Debug\lib\cmake\Qt5Xlsx ⇒ F:\Software\Qt\5.15.2\msvc2019\lib\cmake)。

3.6项目使用过的qss样式

/* 设置表格滚动条样式 */
QTableView QScrollBar:vertical {
  background: #d8dfe7;
  width: 12px;
  border-radius: 6px;
}
QTableView QScrollBar::handle:vertical {
  background: #a2a1ab;
  width: 12px;
  border-radius: 6px;
  min-height: 100px;
}
QTableView QScrollBar::handle:vertical:hover {
  background: #82818b;
}

QTableView QScrollBar:horizontal {
  background: #d8dfe7;
  height: 12px;
  border-radius: 6px;
}
QTableView QScrollBar::handle:horizontal {
  background: #a2a1ab;
  height: 12px;
  border-radius: 6px;
  min-width: 100px;
}
QTableView QScrollBar::handle:horizontal:hover {
  background: #82818b;
}

/* 设置下拉框子项样式 */
QComboBox QAbstractItemView::item {
  min-height: 25px;
  padding-left: 3px;
}

/* 设置表格中文件上传按钮样式(带下划线的按钮,鼠标手样式只能通过代码设置) */
QPushButton[filebutton]{
  border: none;
  background: none;
  text-decoration: underline;
  color: #008b45;
}

/* 设置表头排序按钮样式 */
#LibraryPanel QHeaderView[direction="horizontal"]::down-arrow { 
	subcontrol-position: center right;
	image: url(:/ui/ui/down.png);
	padding-right: 8px;
}
#LibraryPanel QHeaderView[direction="horizontal"]::up-arrow { 
	subcontrol-position: center right;
	image: url(:/ui/ui/up.png);
	padding-right: 8px;
}

/* 设置QTabWidget模块样式 */
#tabWidgetModule::pane {
  border-top: 1px solid #97aad3;
  border-bottom: 1px solid #97aad3;
  position: absolute;
  top: -1px;
  padding-left: 20px;
  background-color: #cfd6e5;
}
#tabWidgetModule > QTabBar::tab {
  min-width: 100px;
  min-height: 30px;
  border-bottom: 1px solid #97aad3;
  background-color: #eceff6;
  font-size: 14px;
  color: #000000;
}
#tabWidgetModule > QTabBar::tab:selected {
  background-color: #293955;
  color: #ffffff;
}
#tabWidgetModule > QTabBar::tab:hover {
  font-size: 16px;
}

3.7控制QAbstractTableModel某列不可编辑

通过派生QAbstractTableModel,重写Qt::ItemFlags flags(const QModelIndex& index) const函数来实现。

/* MyTableModel.cpp */
//重写flags函数
Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const{
	auto flags = QAbstractTableModel::flags(index);
	int columnNoEditable=3;//不可编辑的列,自己定义
	if(index.column()==3){
		return flags;//不可编辑
	}else{
		return flags|Qt::ItemIsEditable;//可编辑
	}
}

注意:如果表格列column是不可编辑的,则将无法给该列的所有单元格赋值,代码赋值也不行,即model->setData(row,column,“value”)是无效的。

解决的方法:在setData之前先设置单元为可编辑状态,赋值后再改为不可编辑状态。

3.8QTableView+QSqlTableModel实现排序功能

1. 实现方式
主要编码:调用QHeaderView的setSortIndicator、setSortIndicatorShown函数、QSqlTableModel的sort函数,将QHeaderView排序状态切换信号(sortIndicatorChanged)绑定到QSqlTableModel数据切换排序(自己写)。

//需要排序且表格显示时初始排序的列
int columnSorted=0;

//设置初始排序的列,排序方式为升序
ui->tableView->horizontalHeader()->setSortIndicator(columnSorted, Qt::SortOrder::AscendingOrder);

//显示排序按钮,按钮样式可以通过QHeaderView::down-arrow、QHeaderView::up-arrow设置
ui->tableView->horizontalHeader()->setSortIndicatorShown(true);

//进行排序
m_sqlTableModel->sort(m_sortFieldColumns.at(0),::SortOrder::AscendingOrder);

//信号绑定
connect(ui->tableView->horizontalHeader(),::sortIndicatorChanged, 
		this,[=](int logicalIndex, Qt::SortOrder order) {
		m_sqlTableModel->sort(logicalIndex, order);
		});

2. 解决问题
由于QHeaderView的setSortIndicatorShown(true)函数调用后会,表格所有列都将出现排序按钮,因此需要解决这个问题,解决方法:派生QHeaderView,重写mousePressEvent、mouserReleaseEvent函数,在函数中将非排序列的表头点击事件过滤掉,最后为QTableView设置自定义的表头。

/* MyTableHeaderView.cpp */
MyTableHeaderView::SortTableHeaderView(const std::vector<int> &sortColumns,
                                         QWidget *parent)
    : QHeaderView(Qt::Horizontal, parent) {
  m_sortColumns = sortColumns;//排序列集合
}
void MyTableHeaderView::mousePressEvent(QMouseEvent *e) {
  const int index = logicalIndexAt(e->pos());
  if (std::find(m_sortColumns.begin(), m_sortColumns.end(), index) ==
      m_sortColumns.end()) {
    setSectionsClickable(false);
  }
  QHeaderView::mousePressEvent(e);
  setSectionsClickable(true);
}

void MyTableHeaderView::mouseReleaseEvent(QMouseEvent *e) {
  const int index = logicalIndexAt(e->pos());
  if (std::find(m_sortColumns.begin(), m_sortColumns.end(), index) ==
      m_sortColumns.end()) {
    setSectionsClickable(false);
  }
  QHeaderView::mouseReleaseEvent(e);
  setSectionsClickable(true);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值