Qt控件的使用

一、非常不错的Qt博客

一去二三里 飞扬青云@gitee  飞扬青云@csdn 飞扬青云@cnblogs 花狗Fdog    界面合集     长沙红胖子   Qt各控件的视频讲解
---------------------------------------------
界面美化系列视频1
界面美化系列视频2
界面框架视频
Qt自定义标题栏视频
Qt 开源项目收集大全
qt常用开源控件库
Qt开源炫酷界面QCoolPage
Qt界面开发【各种控件以及图表】
QT 开源类库集合
Qt-Open-Source-Project各种开源库链接
网易云音乐模仿系列视频-----重绘标题栏
pyqt界面视频集合
QWidget设置背景图片

二、界面例子

qt-material-widgets的GitHub地址
界面定制:
PyDracula - 界面美化模板【视频】
PyDracula【Github地址】
QtDracula【Github地址】

Qt控件的使用_第1张图片

自定义悬浮条
Qt控件的使用_第2张图片
Qt利用"布局、widget、ScrollArea"实现抽屉效果

Qt控件的使用_第3张图片

可自由展开的ToolBox
Qt控件的使用_第4张图片

自定义标题栏
实现窗口透明的五种方法(长沙红胖子)

//透明窗体中的圆形按钮(按钮不透明)
setAttribute(Qt::WA_TranslucentBackground,  true );
    QPalette pal = palette();
    pal.setColor(QPalette::Background, QColor(0x00,0xff,0x00,0x00));
    setPalette(pal);
    setWindowFlags(windowFlags() | Qt::FramelessWindowHint);

    setStyleSheet("QPushButton{ color: green; background: #f44336; font-size: 10px; border:1px solid red; "
                  "min-width:60; max-width:60; min-height:60; max-height:60;border-radius:30px;border-image:url(:/home.png);}"
                  "QPushButton:hover { font-size: 10px; color: white; background: #d5d5d5; border-image:url(:/set.png); } "
                  "QPushButton:pressed { background: #f2f2f2;}");

飞机飞行状态综合显示控件
小罗博客目录汇总

飞行仪表控件
Qt控件的使用_第5张图片

QtSwissArmyKnife开发工具
Qt控件的使用_第6张图片

QtWaitingSpinner页面加载旋转等待
Qt控件的使用_第7张图片

---------------------------------------------

三、单个控件

1、布局

qt 如何设计好布局和漂亮的界面
Qt 界面设计总结
Qt 之水平/垂直布局(QBoxLayout、QHBoxLayout、QVBoxLayout)

setMargin(0);
setSpacing(0);
setContentsMargins(0,0,0,0);
pHLayout->addStretch();  // 添加伸缩
setStretch(0,80);
setStretch(1,20);
addWidget(m_mainSplitter);
pHLayout->addWidget(pButton1, 0 , Qt::AlignLeft | Qt::AlignTop);
pHLayout->addWidget(pButton4, 0 , Qt::AlignLeft | Qt::AlignBottom);

重新LayOut要先清楚子窗体的parent
布局中的间隔

  • 1、addSpacing(int size)在layout的控件之间插入间距,其插入的间距是在setSpacing(int)的基础上的,即是layout的控件间的间距为addSpacing值+setSpacing值。
    需要注意的是layout布局的控件之间是有默认距离为10(即setSpacing默认设置为10)通过setSpacing(0)函数设置为0可使控件紧贴。>
  • 2、addStretch(int stretch = 0)是在layout的控件之间插入stretch个控件的间距。
  • 3、addSpacerItem(QSpacerItem(int w, int h,QSizePolicy::Policy hData = QSizePolicy::Minimum,QSizePolicy::Policy vData = QSizePolicy::Minimum))
    一般用在控件大小不等的时候。例如窗口的标题栏:部分控件的大小不变,空白区域允许拉长或缩短时。
  • 4、 需要注意的是当你设置了某些控件的大小时,再使用layout布局可能会有出乎意料的情况应该是两者之间存在了冲突。

2、QSplitter

QSplitter(分离部件)
QSplitter布局的两种方法:addWidget、父对象

QTextEdit *pEdit1=new QTextEdit(this);
QTextEdit *pEdit2=new QTextEdit(this);
QTextEdit *pEdit3=new QTextEdit(this);
pEdit1->setText("1");
pEdit2->setText("2");
pEdit3->setText("3");

QSplitter *pSplitterV=new QSplitter(Qt::Vertical,this);//上下分
pSplitterV->addWidget(edit1);//按顺序压入
pSplitterV->addWidget(edit2);

QSplitter *pSplitterH=new QSplitter(Qt::Horizontal,this);//左右分
pSplitterH->addWidget(pSplitterV);
pSplitterH->addWidget(edit3);
QVBoxLayout *pMainLayout = new QVBoxLayout(this);
pMainLayout->addWidget(pSplitterH)
-----------
|    |     |
|----|     |
|    |     |
------------

3、QFrame

用QFrame做横线分隔条:
Qt控件的使用_第8张图片

3、QTabWidget

QTabWidget添加自定义样式
对Tab页布局,是将要布局的Tab页点击为当前Tab页,而后在右侧点击QTabWidget进行布局,就是对Tab页布局了。这个还是让人有点费解,对子页布局居然是对父窗体进行布局。

//去除选项卡的关闭按钮
tabWidget->tabBar()->setTabButton(0, QTabBar::RightSide, nullptr);

QTabWidget边框的右边和下边,都多出了一条白边。大概2px宽
解决方法:
QTabWidget的documentMode属性复选框打钩即可。
取消documentMode后,选项卡下边会有一条白线,可在样式表里设置:

QTabWidget { border-top-color: rgba(255, 255, 255, 0); } 

发现tabbar上面有一根线始终去不掉

QTabBar {
    qproperty-drawBase: 0;
}

当tab个数大于一定个数时,会出现如下图左侧白线所示,这个是Qt自带的,作用是点击回到第一个tab,隐藏方法:

QTabBar::tear {
    width: 0px; 
    border: none;
}

4、QTableWidget

QTableWidget详解(样式、右键菜单、表头塌陷、多选等)
QTableWidget布局控件
Qt 笔记(1) 为QTableWidget设置自定义代理(myTable.zip)
QTableWidget实现QComboBox的代理且发送信号实现联动
设置代理
comb代理
常用代理总结
QTableWidget内存清理
QTableWidgetItem的析构
QTableWidget加载百万条数据不卡

(1)基本操作

ui->tableWidget->horizontalHeader->setSectionResizeMode(QHeaderView::ResizeToContens);
ui->tableWidget->setColumnCount(list.size());
ui->tableWidget->setHorizontalHeaderLabels(list);
ui->tableWidget->setDefaultValue(valueList);
ui->tableWidget->setItemDelegateForColumn(0,new QSpinBoxDelegate(32768,this));

//--------
ui->tableWidger->setColumncount(3);
ui->tableWidger->setHorizontalHeaderLabels(QStringList()<<"姓名"<<"性别"<<"年龄";
ui->tableWidger->setRowCount(5);
//ui->tableWidger->setItem(0,0,new QTableWidgetItem("张三"));
QList<QString> nameList;
nameList<<"张三"<<"李四"<<"王五"<<"张龙"<<"赵虎";
QStringList sexList;
sexList<<"男"<<"男"<<"女"<<"男"<<"女";
for(int i=0; i<5; i++)
{
	int col=0;
	ui->tableWidger->setItem(i,col++,new QTableWidgetItem(nameList[i]));//[]会直接崩掉
	ui->tableWidger->setItem(i,col++,new QTableWidgetItem(nameList.at(i)));//at()会抛出异常
	ui->tableWidger->setItem(i,col++,new QTableWidgetItem(QString::number(18+i)));
}

(2)单击响应及获取内容

cell是一个绝对存在的容器,而item是一个被填入到cell中的一个实体,可以有也可以没有。
无论单元格中有没有 值,cellClicked()都能被发出,说明不管有没有值,都有这个容器在。
在单元格有值的情况下,itemClicked()才能被发出,说明必须要有值才有发出信号的实体。

connect(ui->tableWidget,&QTableWidget::itemClicked,this,&MainWindow::enter);
connect(ui->tableWidget,&QTableWidget::cellClicked,this,&MainWindow::enter);
// 返回鼠标单击的所在单元格的row和col
void PageProductInfo::show_prodcut_sets(int row,int col)
{
	qDebug() << "所点击的单元格的row=" << row << ",col=" << col;
	// 获取所点击的单元格
    QTableWidgetItem* item = ui->tableWidget_right->item(row ,col); 
    qDebug() << item->text();	
}
void MainWindow::gettheitem()
{
    //获取当前点击的单元格的指针
    QTableWidgetItem* curItem = ui->tableWidget->currentItem();
    //获取单元格内的内容  
    QString wellName = curItem->text();
    //输出内容
    qDebug() << wellName;
}
QPushButton *button = dynamic_cast<QPushButton *>(QObject::sender()); //找到信号发送者
QModelIndex index = ui->tableWidget->indexAt(button->pos());  //定位按钮
QTableWidgetItem *item = ui->tableWidget->item(index.row(), 0);  //得到item

(3)添加控件到item上

QTableWidget::setCellWidget(int row, int column, QWidget *widget)//设置表格某行某列为QWidget
QTableWidget::setItem(int row, int column, QTableWidgetItem *item)//设置表格某行某列内容为QTableWidgetItem
QTableWidget::setCurrentCell(int row, int column, QItemSelectionModel::SelectionFlags command)//使用cell要有行列
QTableWidget::setCurrentItem(QTableWidgetItem *item, QItemSelectionModel::SelectionFlags command)

(4)右键菜单

m_pTableWidget->setContextMenuPolicy(Qt::CustomContextMenu);
QMenu * m_pTableMenu = new menu(m_pTableWidget);
connect(m_pTableWidget, &QTableWidget::customContextMenuRequested, this, [=](){
    m_pTableMenu->exec(QCursor::pos());
});
QAction *pAction = new QAction("删除");
m_pTableMenu->addAction(pAction);
connect(pAction, &QAction::triggered, [=](){   });
ui->tableWidget->setContextMenuPolicy(Qt::CustomContextMenu);     
m_tabMenu = new QMenu(ui->tableWidget);			//右键
action= new QAction("展示最近数据",this);
m_tabMenu->addAction(action);
connect(ui->tableWidget, SIGNAL(customContextMenuRequested(QPoint)),
				   this, SLOT(slot_DL_RcOnTw(QPoint)));
connect(action,SIGNAL(triggered(bool)),this,SLOT(slotActionInsert()));

void MainWindow::slot_DL_RcOnTw(QPoint pos)
{
    m_tabMenu->exec(QCursor::pos());
}

右键删除所在行:
QTableView删除行,列

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    model = new QStandardItemModel;
    QStringList slt;
    slt<<QString::fromUtf8("第一列")<<QString::fromUtf8("第二列")<<QString::fromUtf8("第三列");
    model->setHorizontalHeaderLabels(slt);
    ui->tableView->setModel(model);
    QList<QStandardItem *> qlist;
    qlist << new QStandardItem("q")<<new QStandardItem("w")<<new QStandardItem("e");
    model->appendRow(qlist);
    qlist.clear();
    qlist << new QStandardItem("qq")<<new QStandardItem("ww")<<new QStandardItem("ee");
    model->appendRow(qlist);
    qlist.clear();
    qlist << new QStandardItem("qqq")<<new QStandardItem("www")<<new QStandardItem("eee");
    model->appendRow(qlist);
    qlist.clear();

    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);//设置选择元素,以元素为单位
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);//设置选择模式,

//    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选择行行为,以行为单位
//    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);//设置选择模式,选择单行

    //ui->tableView->setSelectionBehavior(QAbstractItemView::SelectColumns);//设置选择列行为,以列为单位
    //ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);//设置选择模式,选择单列

    ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);//右键点击菜单
    menu = new QMenu(ui->tableView);
    act = new QAction("删除当前行",this);
    actcol = new QAction("删除当前列",this);
    menu->addAction(act);
    menu->addAction(actcol);

    connect(ui->tableView,SIGNAL(customContextMenuRequested(QPoint)),this,SLOT(rightclickslot(QPoint)));
    connect(act,SIGNAL(triggered(bool)),this,SLOT(deleteslotrow()));
    connect(actcol,SIGNAL(triggered(bool)),this,SLOT(deleteslotcol()));


}

void MainWindow::rightclickslot(QPoint pos)
{
    QModelIndex index = ui->tableView->indexAt(pos);
    currentrow = index.row();			//保存所选行
    currentcol = index.column();
    qDebug()<<"index.data()"<<index.data().toString();
    qDebug()<<"model->data(index)"<<model->data(index).toString();
    qDebug()<<"currentrow"<<currentrow;
    qDebug()<<"currentcol"<<currentcol;
    if(index.isValid())
        menu->exec(QCursor::pos());
}
void MainWindow::deleteslotrow()
{
    QMessageBox message(QMessageBox::NoIcon,QString::fromUtf8("提示"),QString::fromUtf8("是否删除本行数据"),
                        QMessageBox::Yes | QMessageBox::No,NULL);
    //如确认删除
    if(message.exec() == QMessageBox::Yes)
    {
        model->removeRow(currentrow);
    }
}
void MainWindow::deleteslotcol()
{
    QMessageBox message(QMessageBox::NoIcon,QString::fromUtf8("提示"),QString::fromUtf8("是否删除本列数据"),
                        QMessageBox::Yes | QMessageBox::No,NULL);
    //如确认删除
    if(message.exec() == QMessageBox::Yes)
    {
        QMessageBox::information(NULL,QString::fromUtf8("提示"),QString::fromUtf8("就不让你删"));
        //model->removeColumn(currentcol);
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

QTableView右键删除(没在有效行上不弹出)

m_rightClickMenu = new QMenu(this);               			//右键点击菜单
auto deleteAction = new QAction(tr("删除"), this);          //删除事件
m_rightClickMenu->addAction(deleteAction);    				//将action添加到菜单内
connect(ui->tableView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(SLot_Measure_Table_Click_Ritht_Menu(QPoint)));
connect(deleteAction,&QAction::triggered,this,[=]()
    {
        QList<int> rows;
        QItemSelection selection = ui->tableView->selectionModel()->selection();
        for (const QItemSelectionRange &selectionRange : selection)
        {
            for (int row = selectionRange.top(); row <= selectionRange.bottom(); ++row)
                rows.append(row);
        }
        qSort(rows.begin(), rows.end(), qGreater<int>());
        for (int row : rows)
            m_model->removeRow(row);
    });
void MainWidget::SLot_Measure_Table_Click_Ritht_Menu(QPoint pos)
{
    QModelIndex index = ui->tableView->indexAt(pos);    //找到tableview当前位置信息
    if (index.isValid())        //如果行数有效,则显示菜单
    {
        m_rightClickMenu->exec(QCursor::pos());
    }
}

(5)分页

QTableView的分页栏_制作
QTableView分页栏_使用

ui->tableWidget->setItemDelegateForColumn(0, new QDoubleSpinBoxDelegate(30.000,3.000,3,this);
ui->tableWidget->item(i,1)->data(Qt::DisplayRole).toDouble()*1e6;
m_pModel = new QStandardItemModel(this);
m_pModel->setHorizontalHeaderLabels(QStringList()<<"频率"<<"带宽");
ui->tableView->setModel(m_pModel);
m_pModel->romoveRows(0,m_pModel->rowCounts());
QList<QStandardItem*> itemList;
itemList.append(new QStandardItem(QString::number(freq/1e6,'f',6)));
m_pModel->insertRow(0,itemList);

QTableView固定某列宽 其他列宽自适应填充伸展
注:列宽的设置需要放在setModel之后,否则会出现异常现象

horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);  //所有列都扩展自适应宽度,填充充满整个QTableView宽度
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);//对第0列单独设置固定宽度
setColumnWidth(0, 50);//设置固定宽度

ui->tableWidget->scrollToBottom();  //让滚动条滚动到最底部
ui->tableWidget->scrollToTop();  //让滚动条滚动到最顶部

不可编辑:

ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);//不可编辑

4.6 代理

//.h 文件
class GComboxDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    GComboxDelegate(QObject * parent = nullptr);
    ~GComboxDelegate();
    
	//编辑单元格时调用函数
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;

	//取单元格里面的内容更新QComboBox的值
    void setEditorData(QWidget *editor, const QModelIndex &index) const;

	//QComboBox的值设置到单元格中,在这里面可以发送消息
    void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const;

signals:
    void OnEmitCurrentIndexChangeSignal(int iRow, int iColumn , int iId ) const;  //定义消息必须有const

private:
};
//.cpp中

//编辑单元格时调用函数
QWidget *GComboxDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if ( index.isValid() && index.column() == 1 )  // 1 代表列
    {
        QComboBox *editor = new QComboBox(parent); //创建QComboBox
        editor->setEditable(true);
        editor->installEventFilter(const_cast<GComboxDelegate *>(this));
        return editor;
    }
    else
    {
        return QItemDelegate::createEditor(parent, option, index);
    }
}

//取单元格里面的内容更新QComboBox的值
void GComboxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    if ( index.isValid() && index.column() == 1)  // 1 代表列
    {
        QString value = index.model()->data(index, Qt::DisplayRole).toString();  //取单元格内容更新QComBoBox
        QComboBox *combox = static_cast<QComboBox *>(editor);

        combox->addItem( "男" );  //QComboBox中增加可选项
        combox->setItemData(0, 1,Qt::UserRole); //增加附加数据
        combox->addItem( "女" );  //QComboBox中增加可选项
        combox->setItemData(1, 1,Qt::UserRole); //增加附加数据     
        combox->setCurrentText(value); //设置选择项
    }
    else
    {
        QItemDelegate::setEditorData(editor, index);
    }
}

 

//QComboBox的值设置到单元格中,在这里面可以发送消息
void GComboxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    if ( index.isValid() && index.column() == 1 ) //1代表列
    {
        QComboBox *combox = static_cast<QComboBox *>(editor);  
        model->setData(index, combox->currentText(), Qt::DisplayRole);  //设置单元格内容
        int iType= combox->currentData(Qt::UserRole).toInt();  //取出当前选中的QComboBox的附加数据
        model->setData(index, iType, Qt::UserRole); //设置单元格附加数据
        emit OnEmitCurrentIndexChangeSignal(index.row(),index.column(), iType);   //发送信号,实现其它联动更新

    else
    {
        QItemDelegate::setModelData(editor, model, index);
    }
}

 

//使用代理
GComboxDelegate   IdentityType = new GComboxDelegate(this); //定义变量
ui->tableWidget->setItemDelegateForColumn(1, IdentityType ); //第一列设置代理
connect(IdentityType, SIGNAL(OnEmitCurrentIndexChangeSignal(int,int,int)), this, SLOT(OnIndexChangeSlot(int,int,int))); //绑定信号槽函数,在槽函数中处理联动信息。

 

//槽函数定义

public slots:
    void OnIndexChangeSlot(int iRow,int iColumn,int iType);  //可不加const

5、QTableView

QTableView基本使用
Qt Model/View 学习(5) - QTableView(优雅)使用教程
QTableView实现鼠标悬浮(hover)行高亮显示
QStandardItemModel(2.超级详细函数)
Qt控件的使用_第9张图片

// 遍历QTableView所有行 
int rows = ui->tableView1->model()->rowCount();
for(int r = 0; r < rows; r++)
{
    qDebug() << ui->tableView1->model()->index(r,0).data().toString();
}
 
 // QTableView选中所有行
QItemSelectionModel *selections =  ui->tableView1->selectionModel();
QModelIndexList selected = selections->selectedRows(); 
for (int i = 0; i < selected.count(); i++)
{
    QString name = standardItemModel->index(selected.at(i).row(), 0).data().toString();
}

5.1 QStandardItemModel

解决QTableview加载百万行数据卡顿问题:核心思想是将model放入线程中

QStandardItemModel* model = new QStandardItemModel();	//创建数据模型
QItemSelectionModel *theSelection; //选择模型
ui->tableView->setModel(model);   
model->setHorizontalHeaderLabels({"学号", "姓名", "考试题目"});    
ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
model->setItem(row, col, new QStandardItem("text"));

theSelection = new QItemSelectionModel (model) ;//选择模型
connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)), this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
ui->tableView->setSelectionModel(theSelection); //设置选择模型
ui->tableView->setSelectionMode(QAbstractItemView::ExtendedSelection);
//ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);//设置选中模式为选中行
ui->tableView->setSelectionMode ( QAbstractItemView::SingleSelection);//禁止选择多行
void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{ //选择单元格变化时的响应
    if (current.isValid())
    {
        LabCellPos->setText (QString::asprintf ("当前单元格:%d 行,%d 列", current.row(),current.column()));
        QStandardItem* aItem=theModel->itemFromIndex(current);
        this->LabCellText->setText ("单元格内容:"+aItem->text());
        QFont font=aItem->font();
        ui->actFontBold->setChecked(font.bold());
    }
}

5.2 QAbstractTableModel

QAbstractTableModel[官翻]
QAbstractTableModel基本操作
QAbstractTableModel基本使用:数据加载以及增删行列
QTableView Optimization
Qt中QTreeview、QLIstView、QTableview等更新数据model时内存泄漏的问题
解决内存泄漏的方法是:将model删除,并重新给view赋新model。原因是QAbstractTableModel自身并没有清空占用的内存。

void setData()
{
	delete ui->tableView->model();
	ui->tableView->setModel(nullptr);	// 或新model
}
void Widget::onDeleteALLTriggered()
{
    int count=m_pModel->rowCount();
    m_pModel->removeRows(0,count);
}

继承QAbstractTableModel,必须实现3个纯虚函数rowcount,columncount,data。
rowCount 代表 table 总的行数,columnCount 代表 table 总的列数,data 代表某个单元格的内容(最重要的函数),headerData 代表每一列(或每一行)表头的内容

这个是使用QMap的:QTableView效率优化2 - 自定义Model秒级加载百万行数据
这个是使用QList的:qtableview及自定义model的使用

#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H

#include 
#include 

struct ModelItem {
   QString id;
   QString name;
   QString one;
   QString two;
   QString three;
   QString four;
   QString five;
   QString six;
};

class MyTableModel : public QAbstractTableModel
{
    Q_OBJECT
public:
    explicit MyTableModel(QObject *parent = nullptr);
    ~MyTableModel();


   int rowCount(const QModelIndex &parent = QModelIndex())const override;
   int columnCount(const QModelIndex &parent = QModelIndex())const override;
   QVariant data(const QModelIndex &index, int role = Qt::DisplayRole)const override;
   QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
   bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
   //bool insertRows(int row, int count,const QModelIndex &parent = QModelIndex());
   virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex());

   void SetDeleteList(QList<int> i_List);

    void SetHeadData(QStringList i_list);

    void SetModelData(QList<ModelItem> model);



signals:

private:
    QList<ModelItem> modelData;
    QStringList headeList;
    QList<int> m_DeleteList;

};


#endif // MYTABLEMODEL_H
#include "mytablemodel.h"
#include 
#include 


MyTableModel::MyTableModel(QObject *parent)
{


}

MyTableModel::~MyTableModel()
{

}

int MyTableModel::rowCount(const QModelIndex &parent) const
{
    return modelData.count();
}

int MyTableModel::columnCount(const QModelIndex &parent) const
{
    return headeList.size();
}

QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
    {
        if (section < headeList.size())
        {
            return headeList[section];
        }
    }
    return QAbstractItemModel::headerData(section, orientation, role);
}

bool MyTableModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
    if(!index.isValid())
        return 0;
    if(role == Qt::DisplayRole || role == Qt::EditRole)
    {
        const int row=index.row();
        switch(index.column())
        {
        case 0: modelData[row].id=value.toString();break;
        case 1:modelData[row].name=value.toString();break;
        case 2:modelData[row].one=value.toString();break;
        case 3:modelData[row].two=value.toString();break;
        case 4:modelData[row].three=value.toString();break;
        case 5:modelData[row].four=value.toString();break;
        case 6:modelData[row].five=value.toString();break;
        case 7:modelData[row].six=value.toString();break;

        }
        emit dataChanged(index, index, QVector<int>() << role);
        return true;
    }
    return false;
}


//bool MyTableModel::insertRows(int row, int count,const QModelIndex &parent)
//{
    if(row<0||count<1||row>rowCount())
           return false;
       //需要将操作放到beginInsertRows和endInsertRows两个函数调用之间
       beginInsertRows(parent, row, row + count - 1);
       for(int i=row;i<row+count;i++)
       {
           //在接口对应行插入空数据
           modelData.insert(i,ModelItem);
       }
       endInsertRows();
//    //       return true;
//}

bool MyTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
    if(row<0||count<1||row+count>rowCount())
        return false;
    //需要将操作放到beginRemoveRows和endRemoveRows两个函数调用之间

    beginRemoveRows(parent, row, row + count - 1);

    if(m_DeleteList.size()!=0)
    {
        for(int i=0;i<m_DeleteList.size();i++)
        {
            modelData.removeAt(m_DeleteList[i]);
        }
    }

//    for(int i=row+count-1;i>=row;i--)
//    {
//        //移除该行数据
//        modelData.removeAt(i);
//    }
    m_DeleteList.clear();
    endRemoveRows();

    return true;
}

void MyTableModel::SetDeleteList(QList<int> i_List)
{
    m_DeleteList=i_List;
}



QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
    if(!index.isValid())
        return QVariant();
    if(role == Qt::DisplayRole || role == Qt::EditRole)
    {
        const int row=index.row();
        switch(index.column())
        {
        case 0: return modelData.at(row).id;
        case 1:return modelData.at(row).name;
        case 2:return modelData.at(row).one;
        case 3:return modelData.at(row).two;
        case 4:return modelData.at(row).three;
        case 5:return modelData.at(row).four;
        case 6:return modelData.at(row).five;
        case 7:return modelData.at(row).six;
        }
    }
    return QVariant();
}

void MyTableModel::SetHeadData(QStringList i_list)
{
    headeList=i_list;
}

void MyTableModel::SetModelData(QList<ModelItem> model)
{
    modelData=model;
}

添加行、删除行:


bool MyTableModel::insertRows(int row, int count, const QModelIndex &parent)
{
    //row为0就是开始,为rowcount就在尾巴
    if(row<0||count<1||row>rowCount())
        return false;
    //需要将操作放到beginInsertRows和endInsertRows两个函数调用之间
    beginInsertRows(parent, row, row + count - 1);
    for(int i=row;i<row+count;i++)
    {
        //在接口对应行插入空数据
        modelData.insert(i,MyModelItem());
    }
    endInsertRows();
    return true;
}
 
bool MyTableModel::removeRows(int row, int count, const QModelIndex &parent)
{
    if(row<0||count<1||row+count>rowCount())
        return false;
    //需要将操作放到beginRemoveRows和endRemoveRows两个函数调用之间
    beginRemoveRows(parent, row, row + count - 1);
    for(int i=row+count-1;i>=row;i--)
    {
        //移除该行数据
        modelData.removeAt(i);
    }
    endRemoveRows();
    return true;
}

自定义数据:

pItem->setData(Qt::UserRole, QVariant::fromValue(user));  	// 设置用户数据
QVariant variant = item->data(Qt::UserRole);  				// 获取用户数据

QVariant var;
var.setValue(12);
int data=var.toInt();
//自定义结构体
struct MyClass{
    int id;
    QString name;
};
Q_DECLARE_METATYPE(MyClass)
QVariant var = QVariant::fromValue(info);			//结构体
var.setValue(info);
CInfo info= var.value<CInfo>()

5.3 model放在线程中,解决界面卡顿

QThread m_thread;
m_model->moveToThread(&m_thread);    
connect(&m_thread, &QThread::finished, &m_thread,&QObject::deleteLater);
connect(&m_thread, &QThread::finished, m_model, &QObject::deleteLater);
m_thread.start();

5.4 添加大数据时卡顿

//添加数据前:
TableView->setUpdatesEnabled(false);  //暂停界面刷新
...添加大量数据过程...
//添加完毕后:
TableView->setUpdatesEnabled(true);  //恢复界面刷新

5.5 表头排序

默认不显示排序图标,点击表头显示排序图标,进行排序

m_tableView->setSortingEnabled(false);							// 不设置排序    
m_tableView->horizontalHeader()->setSortIndicatorShown(false);	// 隐藏排序图标
// 信号发出,进行排序以及图标显示
connect(m_tableView->horizontalHeader(), &QHeaderView::sortIndicatorChanged, this, [this](int logicalIndex, Qt::SortOrder order) {
    qDebug() << logicalIndex << order;
    if (0 == logicalIndex) {
        this->m_model->sort(0, order);
        m_tableView->horizontalHeader()->setSortIndicatorShown(true);
    }
});

Qt自定义点击表头排序,使支持恢复默认顺序

5、QStackWidget

6、QDockWidget

浮动窗口Advanced-Docking-System

    m_pDock1 = new QDockWidget("参数1", this);
    m_pDock1->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    m_pDock1->setWidget(new ParamWidget1);
    //去除标题栏
    QWidget* lTitleBar = m_pDock1->titleBarWidget();
    QWidget* lEmptyWidget = new QWidget(this);
    m_pDock1->setTitleBarWidget(lEmptyWidget);
    delete lTitleBar;

    m_pDock2 = new QDockWidget("参数2", this);
    m_pDock2->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    m_pDock2->setWidget(new ParamWidget2);
    //去除标题栏
    QWidget* lTitleBar2 = m_pDock2->titleBarWidget();
    QWidget* lEmptyWidget2 = new QWidget(this);
    m_pDock2->setTitleBarWidget(lEmptyWidget2);
    delete lTitleBar2;

    addDockWidget(Qt::RightDockWidgetArea, m_pDock1);
    addDockWidget(Qt::RightDockWidgetArea, m_pDock2);
    tabifyDockWidget(m_pDock1, m_pDock2);
//    m_pDock1->show();
    m_pDock1->raise();
//    m_pDock1->setMaximumWidth(150);
    m_pDock1->setMinimumWidth(150);
    setTabPosition(Qt::AllDockWidgetAreas, QTabWidget::East);

7、QTreeWidget

QTreeWidget添加项目例子
QTreeWidget增删改查
QTreeWidget设置Delegate
QTreeWidget控件使用方法(复选框)
QTreeWidget和QDockWidget
QTreeWidget勾选QTreeWidgetItem的处理
QTreeWidget 弹出右键菜单
QTreeWidget右键菜单
QTreeWidget:拖拽项目
QTreeWidget连线样式设置
QTtreeWidget节点显示隐藏

treeWidget->setStyleSheet("QTreeView::branch {image:none;}");//去掉前面的三角
treeWidget->setStyleSheet("QTreeWidget::branch:has-siblings:!adjoins-item{border-image:none;}");//去掉连线

QTreeWidget 中加入控件——以QPushButton为例:

//添加控件,为item的第几列设置一个widget控件
void QTreeWidget::setItemWidget ( QTreeWidgetItem * item, int column, QWidget * widget )//获取控件,获取item列里面的控件时的方法为:
QWidget * QTreeWidget::itemWidget ( QTreeWidgetItem * item, int column )//添加按钮的例子---setItemWidget()----------
auto topLevelItem = new QTreeWidgetItem();     //创建一个 TreeItem 容器用于后来装载控件
ui->treeWidget->addTopLevelItem(topLevelItem); //目的是添加一行 Item 
//设置 Item 内控件,0 是第几列
QPushButton *topLevelButton = new QPushButton("Top Level Button");
ui->treeWidget->setItemWidget(topLevelItem, 0, topLevelButton);
connect(topLevelButton, &QPushButton::clicked,)),
            this,&Widget::startTask);


//多层--(指定父窗体)----
QTreeWidgetItem *items3 = new QTreeWidgetItem(tree,QStringList(QString("num_13")));
QTreeWidgetItem *item104 = new QTreeWidgetItem(items3,QStringList(QString("item104")));
//多层--(addChild)-----
QStringList strList;
    strList<<"名称"<<"年龄"<<"性别";
    ui->treeWidget->setHeaderLabels(strList);
    ui->treeWidget->header()->setStyleSheet(sstyle);
 
    QTreeWidgetItem *item1 = new QTreeWidgetItem(QStringList()<<"七年级");
    ui->treeWidget->addTopLevelItem(item1); 
    QTreeWidgetItem *item11 = new QTreeWidgetItem(QStringList()<<"小涨"<<"13"<<"男");
    item1->addChild(item11);
    QTreeWidgetItem *item12 = new QTreeWidgetItem(QStringList()<<"小红"<<"14"<<"女");
    item1->addChild(item12);
    QTreeWidgetItem *item13 = new QTreeWidgetItem(QStringList()<<"小丽"<<"13"<<"女");
    item1->addChild(item13);
 
    QTreeWidgetItem *item2 = new QTreeWidgetItem(QStringList()<<"八年级");
    ui->treeWidget->addTopLevelItem(item2); 
    QTreeWidgetItem *item21 = new QTreeWidgetItem(QStringList()<<"小涨"<<"13"<<"男");
    item2->addChild(item21);
    QTreeWidgetItem *item22 = new QTreeWidgetItem(QStringList()<<"小红"<<"14"<<"女");
    item2->addChild(item22);
    QTreeWidgetItem *item23 = new QTreeWidgetItem(QStringList()<<"小丽"<<"13"<<"女");
    item2->addChild(item23);


//--------------------------
//添加一级节点
QTreeWidgetItem *items1 = new QTreeWidgetItem(tree,
                            QStringList(QString("num_1")));
QTreeWidgetItem *items2 = new QTreeWidgetItem(tree,
                            QStringList(QString("num_1")));
QTreeWidgetItem *items3 = new QTreeWidgetItem(tree,
                            QStringList(QString("num_3")));
//查找节点,查找与num_1完全一致的项,并返回其指针列表。
QList<QTreeWidgetItem*> s = tree->findItems("num_1", Qt::MatchFlag::MatchExactly);
// 无情删除
for (auto item : s) {
    delete item;
}
//随着子项的展开,自动出现横滚动条
 m_pTreeList->header()->setHidden(true);
 m_pTreeList->header()->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
 m_pTreeList->header()->setResizeMode(0, QHeaderView::ResizeToContents);
 m_pTreeList->header()->setStretchLastSection(false);
 m_pTreeList->setTextElideMode(Qt::ElideNone);
QTreeWidgetItem *parentItem = ui->treeWidget->topLevelItem(0); //获取顶级节点
QTreeWidgetItem *newItem = new QTreeWidgetItem(parentItem); //创建子节点
newItem->setFirstColumnSpanned(true);  //设置子节点跨越所有列(PS:否则它的宽度只有第一列的宽度)    
CustomWidget *widget = new CustomWidget(this); //初始化 待嵌套的 widget   
ui->treeWidget->setItemWidget(newItem, 0, widget);  //设置 QTreeWidget 嵌套 widget

添加自定义控件的关键是QTreewidget::SetItemWidget方法,而QTreeview没有SetItemWidget这个方法,只能使用QDelegate设置代理实现。

(5)QTreeWidget添加下拉框太大且不上下居中的解决方法

QComboBox *m_pStyle = new QComboBox(this);
m_pStyle->addItems(QStringList()<<"大"<<"小");
m_pStyle->setStyleSheet("min-height:10; QComboBox::down-arrow{min-height:10;}");
QTreeWidgetItem *pTreeItemStyle = new QTreeWidgetItem(pTreeItemTop1);
pTreeItemStyle->setText(0,"样式");
m_pTree->setItemWidget(pTreeItemStyle, 1, m_pStyle);

8、自定义事件

QEvent::Type参数值:
0 - 999:系统保留
1000-65535:用户定义

Qt自定义事件的三种方法
Qt中的消息通知和事件发送
QT事件传递与事件过滤器

9、QPlainTextEdit

//appendPlainText()会一直累加内存,到100行清除
if(ui->plainTextEdit->blockCount()>100)
    {
         ui->plainTextEdit->setPlainText("");
    }
    ui->plainTextEdit->appendPlainText(str);
    
// 删除换行,下次是加到末尾
void ConsoleDialog::appendMessageToEditor(const QString &message)
{
    ui->textEdit->appendPlainText(message);
    ui->textEdit->moveCursor(QTextCursor::End);
    ui->textEdit->textCursor().deletePreviousChar();
}

10、QTextBrowser

    ui->textBrowser->insertPlainText(QString::number(value,'f',6));
    ui->textBrower->textCursor().insertText("aaaa");
    // 文本输出结束后自动换行
    ui->textBrowser->moveCursor(QTextCursor::End);
    ui->textBrowser->append(QString(""));

11、QScrollAera

QScrollArea使用总结
Qt控件的使用_第10张图片

//调整当前显示的区域,仿迅雷设置可用此
ui->scrollArea->ensureVisible(30, position);

//代码加窗体
QGridLayout *pLayout = new QGridLayout();
for(int i = 0; i < 100; i++)
{
    QPushButton *pBtn = new QPushButton();
    pBtn->setText(QString("按钮%1").arg(i));
    pBtn->setMinimumSize(QSize(60,30));   		
    pLayout->addWidget(pBtn);					
}
ui->scrollArea->widget()->setLayout(pLayout);	

13、QCombox

ui->combox->addItem(str);
ui->combox->addItem(str, data);			//绑定数据data
ui->combox->setCurrentIndex(-1); 		//界面为空
ui->combox->setItemData(0,23);
int data = ui->combox->currentData().toInt();
ui->comBox->currentIndex();  			//索引值
ui->comBox->currentText();  			//界面文字
ui->comBox->currentData();  			//绑定值

14、QButtonGroup

addButton()不指定按钮的id,默认是从-2开始,实际经常从0开始,需逐个指定按钮的id。

//.h中
public slots:
    void sltBtnGroupClicked(int nIndex);
//.cpp中
{
    QButtonGroup* pBtnGroup = new  QButtonGroup(this);
    ui->btnCPlush->setCheckable(true);  //重要
    ui->btnJava->setCheckable(true);
    ui->btnPython->setCheckable(true);
    pBtnGroup->addButton(ui->btnCPlush, 0);
    pBtnGroup->addButton(ui->btnJava, 1);
    pBtnGroup->addButton(ui->btnPython, 2);
    void(QButtonGroup:: *btnGroupClicked)(int) = &QButtonGroup::buttonClicked;
    void(QtWidgetsApplication1:: *sltBtnGroupClicked)(int) = &QtWidgetsApplication1::sltBtnGroupClicked;
    connect(pBtnGroup, btnGroupClicked,this, sltBtnGroupClicked);

    // 第一个页面默认选中
    ui.btnCPlush->setChecked(true);
    ui.stackedWidget->setCurrentWidget(ui.btnCPlush);

}

void QtWidgetsApplication1::sltBtnGroupClicked(int nIndex)
{
    ui.stackedWidget->setCurrentIndex(nIndex);
}

16、嵌入式界面库lvgl(第三方)

使用QtCreator创建lvgl开发环境

17、工具栏库(第三方)

Qt开源库-【工具选项卡TabToolBar】

18、QLineEdit (ip输入框)

ip输入框:
在这里插入图片描述

QRegExp rx("\\b(?:(?:25[0-5] | 2[0-4][0-9] | [01]?[0-9][0-9]?)\\.){3}(?:25[0-5] | 2[0-4][0-9] | [01]?[0-9][0-9]?)\\b)");
    ui->leLocalIP->setValidator(new QRegExpValidator(rx,this));
    ui->leLocalIP->setInputMask("000.000.000.000");

Qt编写自定义控件68-IP地址输入框
Qt控件的使用_第11张图片

19、背景透明

setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);// set transparent

20、仪表盘

qt5 仪表控件 码盘 电压表 油表 开源不装逼
汽车仪表控件系列文章
Qt自定义精美的仪表盘控件(汽车仪表、指南针、雷达、摇杆)
Qt精美控件
Qt控件的使用_第12张图片

汽车仪表盘–飞扬青云
汽车仪表盘–飞扬青云2
汽车仪表盘–解析
Qt控件的使用_第13张图片
车速仪表盘

仪表盘

使用QT绘制雷达扫描效果
Qt控件的使用_第14张图片
Qt 雷达模拟仿真工具
Qt控件的使用_第15张图片
飞机仪表(飞扬青云)
Qt控件的使用_第16张图片
表盘(青云)
Qt控件的使用_第17张图片
圆弧仪表盘(青云)
Qt控件的使用_第18张图片
速度仪表盘
Qt控件的使用_第19张图片
云台仪表盘
Qt控件的使用_第20张图片
温度计
Qt控件的使用_第21张图片
柱状标尺
Qt控件的使用_第22张图片
Qt开源炫酷界面QCoolPage–CylinderControl
Qt控件的使用_第23张图片

可输入仪表
Qt控件的使用_第24张图片
仪表盘
Qt控件的使用_第25张图片

仪表盘

一款有意思的qt飞行仪表控件
https://github.com/wyyrepo/QFlightInstruments
Qt控件的使用_第26张图片
Cockpit-GUI-Design
Qt控件的使用_第27张图片
Qt飞行器仪表盘库(无代码)
Qt控件的使用_第28张图片

飞行仪表
Qt控件的使用_第29张图片
Qt编写自定义控件38-高亮按钮
Qt控件的使用_第30张图片
自绘指南针控件
Qt控件的使用_第31张图片

21、QtPropertyBrowser

早期版本
早期版本使用例子
5.12版源码
官方持续更新版(5.12可用)
QtPropertyBrowser(GitHub下载)
QtnProperty第三方
QtTreePropertyBrowser使用示例
Qt属性表控件的使用 QtTreePropertyBrowser
QtTreePropertyBrowser表头、遍历
qtTteePropertyWidget添加按钮

QtPropertyBrowser 包括:

  • QtTreePropertyBrowser(QTreeView)
  • QtGroupBoxPropertyBrowser
  • QtButtonPropertyBrowser

21.1 基本用法

m_pVarManager = new QtVariantPropertyManager(ui->propertyWidget);
m_pVarFactory = new QtVariantEditorFactory(ui->propertyWidget);
connect(m_pVarManager, &QtVariantPropertyManager::valueChanged, this, &Widget::slt_propertyValueChanged);
//树控件单击的项名称
void Widget::initPropertyWidget(QString name)
{
   ui->propertyWidget->clear();
   m_vItems.clear();
   QtVariantProperty *pItem = m_pVarManager->addProperty(QtVariantPropertyManager::enumTypeId(), "下拉框");
   pItem->setAttribute("enumNames", QStringList()<<"选项0"<<"选项1");
   pItem->setValue(1);
   ui->propertyWidget->addProperty(pItem);
   m_vItems.append(pItem);
   m_mapItems.insert("broaditem", pItem);

   pItem = m_pVarManager->addProperty(QVariant::Int, "整数项");
   pItem->setValue(100);
   ui->propertyWidget->addProperty(pItem);
   m_vItems.append(pItem);
   m_mapItems.insert("uuu", pItem);

   pItem = m_pVarManager->addProperty(QVariant::Double, "doble项");
   pItem->setValue(66.8);
   pItem->setAttribute("decimals",3);
   pItem->setAttribute("maximum", 1);
   pItem->setAttribute("maximum", 6000);
   ui->propertyWidget->addProperty(pItem);
   m_vItems.append(pItem);
   m_mapItems.insert("uuu", pItem);

   pItem = m_pVarManager->addProperty(QVariant::String, "信息");
   pItem->setValue("hggfffg");
   QRegExp reg("[(a-z)(A-Z)(0-9)(\u4e00-\u9fa5)(\uFF00-\uFFFF)(\0000-\u00FF)"']{1,50}$");
   pItem->setAttribute("regExp", reg);
}

void Widget::slt_propertyValueChanged(QtProperty *property, const QVariant &value)
{
    if(property == m_mapItems["ddd"])
    {
        double ff = value.toDouble();
    }
    if(property->proPertyName() == "ddd")
    {
        QList<QtProperty*> listProperty = property->subProperties();
        for(int i = 0; i < listProperty.count(); ++i)
        {
            property->removeSubProperty(listProperty.at(i));
        }
        for(int i = 0; i < newCount; ++i)
        {
            QProperty *pProperty = new QtProperty(m_pVarManager);
            pProperty->setPropertyName("工厂1");
            property->addSubProperty(pProperty);

            QtVariantProperty *pItem = m_pVarManager->addProperty(QVariant::double,"资产");
            pProperty->addSubProperty(pItem);
        }
    }
}



21.2修改DateTime显示格式

//qtpropertybrowserutils.cpp
QString QtPropertyBrowserUtils::dateTimeFormat()
{
    return QString("yyyy-MM-dd hh:mm:ss");
}

21.3 checkBox不显示True和False

初次刷新和单击树项时刷新不显示:

void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item)
{
    QtProperty *property = m_itemToIndex[item]->property();
    QIcon expandIcon;
    if (property->hasValue()) {
        const QString valueToolTip = property->valueToolTip();
        const QString valueText = property->valueText();
        item->setToolTip(1, valueToolTip.isEmpty() ? valueText : valueToolTip);
        item->setIcon(1, property->valueIcon());
        item->setText(1, valueText);
        if(valueText == "True" || valueText == "False" )        //不显示true、false----
            item->setText(1, "");

单击checkBox和改变值时不显示:

QWidget *QtCheckBoxFactory::createEditor(QtBoolPropertyManager *manager, QtProperty *property,
        QWidget *parent)
{
    QtBoolEdit *editor = d_ptr->createEditor(property, parent);    
    editor->setChecked(manager->value(property));
    editor->setTextVisible(false);                      //不显示true、false

21.4 QtnProperty(第三方的)

https://github.com/qtinuum/QtnProperty

21.5修改标题

在QtTreePropertyBrowser中添加一个公有函数:

void QtTreePropertyBrowser::setHeaderLables(const QStringList &labels)
{
    d_ptr->m_treeWidget->setHeaderLabels(labels);
}

21.6 D指针和Q指针

Qt : d指针和q指针
pimpl模式(私有化实现)是为了二进制兼容,更新库时不需重新编译。一个主类,一个私有类。

d_ptr:是主类中指向私有类(Private)的指针
q_ptr:是私有类中指向主类的指针

//主类中(QtTreePropertyBrowser)
class QtTreePropertyBrowserPrivate;
class QtTreePropertyBrowser : public QtAbstractPropertyBrowser
{
    Q_OBJECT
public:
    QtTreePropertyBrowser(QWidget *parent = 0);
    ~QtTreePropertyBrowser();
Q_SIGNALS:
    void collapsed(QtBrowserItem *item);
    void expanded(QtBrowserItem *item);
private:
    QScopedPointer<QtTreePropertyBrowserPrivate> d_ptr;			//d指针
    Q_DECLARE_PRIVATE(QtTreePropertyBrowser)
    Q_DISABLE_COPY(QtTreePropertyBrowser)
    Q_PRIVATE_SLOT(d_func(), void slotCollapsed(const QModelIndex &))		//(私有类指针,槽)
    Q_PRIVATE_SLOT(d_func(), void slotExpanded(const QModelIndex &))
    Q_PRIVATE_SLOT(d_func(), void slotCurrentBrowserItemChanged(QtBrowserItem *))
    Q_PRIVATE_SLOT(d_func(), void slotCurrentTreeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *))
 }
 QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent)
    : QtAbstractPropertyBrowser(parent), d_ptr(new QtTreePropertyBrowserPrivate)
{
    d_ptr->q_ptr = this;
    d_ptr->init(this);
    connect(this, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentBrowserItemChanged(QtBrowserItem*)));
}
//私有类中(QtTreePropertyBrowserPrivate)
class QtTreePropertyBrowserPrivate
{
    QtTreePropertyBrowser *q_ptr;						//q指针
    Q_DECLARE_PUBLIC(QtTreePropertyBrowser)
public:
    QtTreePropertyBrowserPrivate();
    void init(QWidget *parent);
    void slotCollapsed(const QModelIndex &index);
    void slotExpanded(const QModelIndex &index);    
    void slotCurrentBrowserItemChanged(QtBrowserItem *item);
    void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *);
}
void QtTreePropertyBrowserPrivate::init(QWidget *parent)
{   
    m_treeWidget = new QtPropertyEditorView(parent);
    //这里用QObject::connect是因为QtTreePropertyBrowserPrivate不是QObject子类
    QObject::connect(m_treeWidget, SIGNAL(collapsed(QModelIndex)), q_ptr, SLOT(slotCollapsed(QModelIndex)));
    QObject::connect(m_treeWidget, SIGNAL(expanded(QModelIndex)), q_ptr, SLOT(slotExpanded(QModelIndex)));
    QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
}
//用到的宏定义(qglobal.h)
#define Q_DECLARE_PRIVATE(Class) \
    inline Class##Private* d_func() \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
    inline const Class##Private* d_func() const \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(d_ptr));) } \
    friend class Class##Private;

#define Q_DECLARE_PRIVATE_D(Dptr, Class) \
    inline Class##Private* d_func() \										//返回d指针
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(Dptr));) } \
    inline const Class##Private* d_func() const \
    { Q_CAST_IGNORE_ALIGN(return reinterpret_cast<const Class##Private *>(qGetPtrHelper(Dptr));) } \
    friend class Class##Private;

#define Q_DECLARE_PUBLIC(Class)                                    \
    inline Class* q_func() { return static_cast<Class *>(q_ptr); } \		//返回q指针
    inline const Class* q_func() const { return static_cast<const Class *>(q_ptr); } \
    friend class Class;

#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()

21.7 整个框架结构

QtTreePropertyBrowser : public QtAbstractPropertyBrowser

class QtTreePropertyBrowser : public QtAbstractPropertyBrowser
class QtAbstractPropertyBrowser : public QWidget
{
	//private类中
    QList<QtProperty *> properties() const;
    QList<QtBrowserItem *> items(QtProperty *property) const;    
    QList<QtBrowserItem *> topLevelItems() const;
}
class QtProperty
{
	QtAbstractPropertyManager * const m_manager;	//d_ptr->m_manager;
private:
    friend class QtAbstractPropertyManager;    		//两个相互friend
};
class QtBrowserItem
{
	//private类中
	QtAbstractPropertyBrowser * const m_browser;
    QtProperty *m_property;
    QtBrowserItem *m_parent;
private:   
    friend class QtAbstractPropertyBrowserPrivate;
};

class QtVariantPropertyManager : public QtAbstractPropertyManager
class QtAbstractPropertyManager : public QObject
{
private:
    friend class QtProperty;    
};

class QtVariantEditorFactory : public QtAbstractEditorFactory<QtVariantPropertyManager>
template <class PropertyManager>
class QtAbstractEditorFactory : public QtAbstractEditorFactoryBase
{
private:
    QSet<PropertyManager *> m_managers;
    friend class QtAbstractPropertyEditor;
};
class QtAbstractEditorFactoryBase : public QObject
{
    friend class QtAbstractPropertyBrowser;
};

class QtVariantEditorFactory : public QtAbstractEditorFactory<QtVariantPropertyManager>
class QtSpinBoxFactory : public QtAbstractEditorFactory<QtIntPropertyManager>
class QtSliderFactory : public QtAbstractEditorFactory<QtIntPropertyManager>
class QtScrollBarFactory : public QtAbstractEditorFactory<QtIntPropertyManager>
class QtCheckBoxFactory : public QtAbstractEditorFactory<QtBoolPropertyManager>
class QtDoubleSpinBoxFactory : public QtAbstractEditorFactory<QtDoublePropertyManager>
class QtLineEditFactory : public QtAbstractEditorFactory<QtStringPropertyManager>
class QtDateEditFactory : public QtAbstractEditorFactory<QtDatePropertyManager>
class QtTimeEditFactory : public QtAbstractEditorFactory<QtTimePropertyManager>
class QtDateTimeEditFactory : public QtAbstractEditorFactory<QtDateTimePropertyManager>
class QtKeySequenceEditorFactory : public QtAbstractEditorFactory<QtKeySequencePropertyManager>
class QtCharEditorFactory : public QtAbstractEditorFactory<QtCharPropertyManager>
class QtEnumEditorFactory : public QtAbstractEditorFactory<QtEnumPropertyManager>
class QtCursorEditorFactory : public QtAbstractEditorFactory<QtCursorPropertyManager>
class QtColorEditorFactory : public QtAbstractEditorFactory<QtColorPropertyManager>
class QtFontEditorFactory : public QtAbstractEditorFactory<QtFontPropertyManager>

int QtVariantPropertyManagerPrivate::internalPropertyToType(QtProperty *property) const
{
    int type = 0;
    QtAbstractPropertyManager *internPropertyManager = property->propertyManager();
    if (qobject_cast<QtIntPropertyManager *>(internPropertyManager))
        type = QVariant::Int;
    else if (qobject_cast<QtEnumPropertyManager *>(internPropertyManager))
        type = QtVariantPropertyManager::enumTypeId();
    else if (qobject_cast<QtBoolPropertyManager *>(internPropertyManager))
        type = QVariant::Bool;
    else if (qobject_cast<QtDoublePropertyManager *>(internPropertyManager))
        type = QVariant::Double;
    return type;
}
QVariant QtVariantPropertyManager::value(const QtProperty *property) const
{    
    QtProperty *internProp = propertyToWrappedProperty()->value(property, 0);
    if (internProp == 0)
        return QVariant();

    QtAbstractPropertyManager *manager = internProp->propertyManager();
    if (QtIntPropertyManager *intManager = qobject_cast<QtIntPropertyManager *>(manager)) {
        return intManager->value(internProp);
    } else if (QtDoublePropertyManager *doubleManager = qobject_cast<QtDoublePropertyManager *>(manager)) {
        return doubleManager->value(internProp);
    } else if (QtBoolPropertyManager *boolManager = qobject_cast<QtBoolPropertyManager *>(manager)) {
        return boolManager->value(internProp);
    } else if (QtStringPropertyManager *stringManager = qobject_cast<QtStringPropertyManager *>(manager)) {
        return stringManager->value(internProp);
    } else if (QtDatePropertyManager *dateManager = qobject_cast<QtDatePropertyManager *>(manager)) {
        return dateManager->value(internProp);
    } else if (QtTimePropertyManager *timeManager = qobject_cast<QtTimePropertyManager *>(manager)) {
        return timeManager->value(internProp);
    } else if (QtDateTimePropertyManager *dateTimeManager = qobject_cast<QtDateTimePropertyManager *>(manager)) {
        return dateTimeManager->value(internProp);
    } else if (QtKeySequencePropertyManager *keySequenceManager = qobject_cast<QtKeySequencePropertyManager *>(manager)) {
        return QVariant::fromValue(keySequenceManager->value(internProp));
    } else if (QtCharPropertyManager *charManager = qobject_cast<QtCharPropertyManager *>(manager)) {
        return charManager->value(internProp);
    } else if (QtLocalePropertyManager *localeManager = qobject_cast<QtLocalePropertyManager *>(manager)) {
        return localeManager->value(internProp);
    } else if (QtPointPropertyManager *pointManager = qobject_cast<QtPointPropertyManager *>(manager)) {
        return pointManager->value(internProp);
    } else if (QtPointFPropertyManager *pointFManager = qobject_cast<QtPointFPropertyManager *>(manager)) {
        return pointFManager->value(internProp);
    } else if (QtSizePropertyManager *sizeManager = qobject_cast<QtSizePropertyManager *>(manager)) {
        return sizeManager->value(internProp);
    } else if (QtSizeFPropertyManager *sizeFManager = qobject_cast<QtSizeFPropertyManager *>(manager)) {
        return sizeFManager->value(internProp);
    } else if (QtRectPropertyManager *rectManager = qobject_cast<QtRectPropertyManager *>(manager)) {
        return rectManager->value(internProp);
    } else if (QtRectFPropertyManager *rectFManager = qobject_cast<QtRectFPropertyManager *>(manager)) {
        return rectFManager->value(internProp);
    } else if (QtColorPropertyManager *colorManager = qobject_cast<QtColorPropertyManager *>(manager)) {
        return colorManager->value(internProp);
    } else if (QtEnumPropertyManager *enumManager = qobject_cast<QtEnumPropertyManager *>(manager)) {
        return enumManager->value(internProp);
    } else if (QtSizePolicyPropertyManager *sizePolicyManager =
               qobject_cast<QtSizePolicyPropertyManager *>(manager)) {
        return sizePolicyManager->value(internProp);
    } else if (QtFontPropertyManager *fontManager = qobject_cast<QtFontPropertyManager *>(manager)) {
        return fontManager->value(internProp);
#ifndef QT_NO_CURSOR
    } else if (QtCursorPropertyManager *cursorManager = qobject_cast<QtCursorPropertyManager *>(manager)) {
        return cursorManager->value(internProp);
#endif
    } else if (QtFlagPropertyManager *flagManager = qobject_cast<QtFlagPropertyManager *>(manager)) {
        return flagManager->value(internProp);
    }
    return QVariant();
}
//自己实现,用于判断是不是bool型property
bool QtVariantPropertyManager::isBoolProperty(const QtProperty *property)
{
    QtProperty *internProp = propertyToWrappedProperty()->value(property, 0);
    if (internProp == 0)
        return false;

    QtAbstractPropertyManager *manager = internProp->propertyManager();
    if (QtBoolPropertyManager *boolManager = qobject_cast<QtBoolPropertyManager *>(manager))
    {
        return true;
    }
    else {
        return false;
    }
}

22、时间轴

自绘时间轴
Qt之时间轴样式汇总

23、QGraphicsView

自定义图元、鼠标划线、右键属性

24. SARibbon、Qt-Advanced-Docking-System

Qt 下结合SARibbon、Dock 开发Opencascade应用的基础框架

Qt控件的使用_第32张图片

25. 仿QQ设置界面

Qt浅谈之三十五仿QQ设置面板功能

Qt控件的使用_第33张图片 [Qt浅谈之三十六仿360设置中心](https://blog.csdn.net/taiyang1987912/article/details/50249243)

26. 窗口动画显示与隐藏

Qt浅谈之四十七下拉列表菜单

Qt浅谈之右下角浮出界面

QT重写QStackedWidget实现home界面左右滑动

QT-QScroller实现home界面上下滑动效果

Qt-滚动字幕之无间隙滚动

27. 侧边栏

Qt–实现侧边栏
Qt控件的使用_第34张图片

Qt私活之实现伸缩滑动窗口
Qt控件的使用_第35张图片

28. 二维码生成与解析

Qt浅谈之三十二二维码条形码解析

29. 音频展示

qt-spek 基于Qt的频谱分析器,修改于spek:
https://github.com/wyyrepo/qt-spek
http://spek.cc/
Qt控件的使用_第36张图片

29、QPushButton

贴图实现方向盘控件
Qt控件的使用_第37张图片

//5个按钮重合在一个位置,而后使用贴图setMask()
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    setAttribute(Qt::WA_TranslucentBackground);

    //设置背景贴图
    QPixmap pixmap;
    pixmap.load(":/assets/bgimage.png");
    resize(pixmap.size());
    setMask(pixmap.mask());
	
    //顶部按钮
    QPixmap topBtn(":/assets/topBtn.png");
    ui->pushButton->setIconSize(topBtn.size());
    ui->pushButton->resize(topBtn.size());
    ui->pushButton->setMask(topBtn.mask());
    ui->pushButton->setStyleSheet("QPushButton{border:0px;border-image:url()}"
                                    "QPushButton:pressed{border-image:url(:/assets/topBtn.png)};");
	//左侧按钮
    QPixmap leftBtn(":/assets/leftBtn.png");
    ui->pushButton_2->setIconSize(leftBtn.size());
    ui->pushButton_2->resize(leftBtn.size());
    ui->pushButton_2->setMask(leftBtn.mask());
    ui->pushButton_2->setStyleSheet("QPushButton{border:0px;border-image:url()}"
                                    "QPushButton:pressed{border-image:url(:/assets/leftBtn.png)};");
	
    //底部按钮
    QPixmap bottomBtn(":/assets/bottomBtn.png");
    ui->pushButton_3->setIconSize(bottomBtn.size());
    ui->pushButton_3->resize(bottomBtn.size());
    ui->pushButton_3->setMask(bottomBtn.mask());
    ui->pushButton_3->setStyleSheet("QPushButton{border:0px;border-image:url()}"
                                    "QPushButton:pressed{border-image:url(:/assets/bottomBtn.png)};");
	//右侧按钮
    QPixmap rightBtn(":/assets/rightBtn.png");
    ui->pushButton_4->setIconSize(rightBtn.size());
    ui->pushButton_4->resize(rightBtn.size());
    ui->pushButton_4->setMask(rightBtn.mask());
    ui->pushButton_4->setStyleSheet("QPushButton{border:0px;border-image:url()}"
                                    "QPushButton:pressed{border-image:url(:/assets/rightBtn.png)};");
	//中间按钮
    QPixmap centerBtn(":/assets/centerBtnImage.png");
    ui->pushButton_5->setIconSize(centerBtn.size());
    ui->pushButton_5->resize(centerBtn.size());
    ui->pushButton_5->setMask(centerBtn.mask());
    ui->pushButton_5->setStyleSheet("QPushButton{border:0px;border-image:url()}"
                                    "QPushButton:pressed{border-image:url(:/assets/centerBtnImage.png)};");
}

Widget::~Widget()
{
    delete ui;
}

void Widget::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing);
    painter.drawPixmap(0,0,QPixmap(":/assets/bgimage.png"));
}

Qt实现自定义按钮的三态效果(好)
Qt控件的使用_第38张图片

pushbutton背景透明:基本都是 setFlat(true) 和 background: transparent

//长按或设为checkable时, 仍会有边框
ui->btn->setStyleSheet("QPushButton{background: transparent;}");
//变形为QToolButton
ui->btn->setStyleSheet("QToolButton{ border-style:falt;}");
Qt控件的使用_第39张图片 Qt控件的使用_第40张图片 Qt控件的使用_第41张图片 Qt控件的使用_第42张图片 Qt控件的使用_第43张图片

Go2Monitor是德国PROCITEC公司开发的一套专业用于无线电信号自动识别,解调,解码,语音检测,信号记录的独立信号分析软件。
Qt控件的使用_第44张图片

30、QProgressBar

Qt实战案例(23)——利用QProgressBar实现彩色进度条

31、QPainter画箭头

Qt控件的使用_第45张图片
void test::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
    painter.setPen(Qt::red);
    painter.setBrush(Qt::red);//设置画笔和画刷
    drawcaricon(&painter);
}
 
void test::drawcaricon(QPainter *painter)
{
    QPoint center, left, right, top;
    center.setX(this->width()/2);			// 中心点
    center.setY(this->height()/2);
    top.setX(center.x());					// 上点
    top.setY(center.y()-150);
    left.setX(center.x()-70);				// 左点
    left.setY(center.y()+70);
    right.setX(center.x()+70);				// 右点
    right.setY(center.y()+70);
 
    QPolygon pts;
    pts.setPoints(4, center.x(), center.y(),
        left.x(), left.y(),
        top.x(), top.y(),
        right.x(), right.y());
    painter->drawConvexPolygon(pts);		//填充绘制多边形
}

32、QWidget保持正方形或比例

思路:resizeEvent

void MyWindow::resizeEvent(QResizeEvent * /*resizeEvent*/)
{
	int width = width();
	int height = height();
	int minSize = width > height ? height : width;
	if(width != height)
		resize(minSize, minSize);
}

思路:对其上部容器进行调整:

void MyWindow::resizeEvent(QResizeEvent * /*resizeEvent*/)
{
    int containerWidth = _myContainerWidget->width();
    int containerHeight = _myContainerWidget->height();

    int contentsHeight = containerHeight ;
    int contentsWidth = containerHeight * _aspectRatio;
    if (contentsWidth > containerWidth ) {
        contentsWidth = containerWidth ;
        contentsHeight = containerWidth / _aspectRatio;
    }

    resizeContents(contentsWidth, contentsHeight);
}

33、QLabel

文字竖着显示(字还是朝上):

m_pLabel->setWordWrap(true);
m_pLabel->setAlignment(Qt::AlignCenter);
m_pLabel->setText(strDisplay.split("",QString::SkipEmptyParts).join("\n"));

文字竖着显示(字还是侧的):
QLabel 如何让文字竖着显示

//继承QLabel,重写virtual void initPainter(QPainter* painter) const 函数
void VLabel::initPainter(QPainter *painter) const
{
	painter->translate(width()/2, height()/2);
	painter->rotate(-90);
	painter->translate(-width()/2, -height()/2);
	QLabel::initPainter(painter);
}
//自定义函数,旋转宽高
void VLabel::rotateLabel()
{
	int m_width = width();
	int m_height = height();
	setFixedWidth(m_height);
	setFixedHeight(m_width);
}

34、对齐方向

控制文字对齐方向:

ui->doubleSpinBox->setAlignment(Qt::AlignRight);//文字右对齐
ui.widget->layout()->setAlignment(Qt::AlignLeft | Qt::AlignTop);

Qt::Alignment 类型有以下取值。

    1)Qt::AlignLeft::  	水平方向靠左。
    2)Qt::AlignRight:		水平方向靠右。
    3)Qt::AlignHCenter:   水平方向居中。
    4)Qt::AlignJustify:   水平方向调整间距两端对齐。
    5)Qt::AlignTop:       垂直方向靠上。
    6)Qt::AlignButton:    垂直方向靠下。
    7)Qt::AlignVCenter:   垂直方向居中。
    8)Qt::AlignCenter:    等价于 Qt::AlignHCenter | Qt::AlignVCenter。

35、QProgressDialog

【QT】数据处理进度等待框QProgressDialog

36、nodeEdit

https://github.com/nwaniek/qt5-node-editor
Qt控件的使用_第46张图片

37、日志

https://github.com/MEONMedical/Log4Qt
加入项目中:include(/src/log4qt/log4qt.pri)

你可能感兴趣的:(QT,qt)