添加自定义HeaderView,支持多行展示,支持每一行的样式设置,支持section大小随内自适配

This commit is contained in:
duanshengchao 2025-03-28 17:40:59 +08:00
parent 8cb6fdd5ae
commit 90e0599dd9
9 changed files with 196 additions and 9 deletions

View File

@ -30,6 +30,7 @@ set(H_HEADER_FILES
include/settings.h include/settings.h
include/tableWidgetHoverDelegate.h include/tableWidgetHoverDelegate.h
include/customMenu.h include/customMenu.h
include/multiLineHeaderView.h
include/modelInfoEditDialog.h include/modelInfoEditDialog.h
include/sqlQueryExecutor.h include/sqlQueryExecutor.h
include/attributeTableModel.h include/attributeTableModel.h
@ -52,6 +53,7 @@ set(CPP_SOURCE_FILES
source/settings.cpp source/settings.cpp
source/tableWidgetHoverDelegate.cpp source/tableWidgetHoverDelegate.cpp
source/customMenu.cpp source/customMenu.cpp
source/multiLineHeaderView.cpp
source/modelInfoEditDialog.cpp source/modelInfoEditDialog.cpp
source/sqlQueryExecutor.cpp source/sqlQueryExecutor.cpp
source/attributeTableModel.cpp source/attributeTableModel.cpp

View File

@ -7,6 +7,7 @@
#include "attributeTableModel.h" #include "attributeTableModel.h"
class QVBoxLayout; class QVBoxLayout;
class MultiLineHeaderView;
class AttributeView : public QWidget class AttributeView : public QWidget
{ {
Q_OBJECT Q_OBJECT
@ -31,6 +32,8 @@ private:
QTableView* m_tableView; QTableView* m_tableView;
AttributeTableModel* m_attributeTableModel; AttributeTableModel* m_attributeTableModel;
QVBoxLayout* m_vLayout; QVBoxLayout* m_vLayout;
MultiLineHeaderView* m_multiLinHeader;
}; };
#endif //ATTRIBUTEVIEW_H #endif //ATTRIBUTEVIEW_H

View File

@ -0,0 +1,37 @@
#ifndef MULTILINEHEADERVIEW
#define MULTILINEHEADERVIEW
#include <QHeaderView>
struct HeaderLineStyle
{
QFont font = QFont("Microsoft YaHei", 9);
QColor color = QColor(26, 26, 26);
Qt::Alignment alignment = Qt::AlignLeft;
};
class MultiLineHeaderView : public QHeaderView
{
Q_OBJECT
public:
explicit MultiLineHeaderView(Qt::Orientation orientation, QWidget* parent = nullptr);
void setLineSpacing(int);
void setBackgroundColor(QColor&);
void setBorderColor(QColor&);
void setSectionLineStyle(int, int, const HeaderLineStyle&); //设置某列的某行文字样式
protected:
void paintSection(QPainter*, const QRect&, int) const override;
QSize sectionSizeFromContents(int) const override;
private:
QHash<int, QMap<int, HeaderLineStyle>> m_sectionStyles; //列号->(行号->样式)
HeaderLineStyle m_defaultStyle;
QColor m_bgColor; //背景颜色
QColor m_borderColor; //边框颜色
int m_linSpacing; //行间距
};
#endif //MULTILINEHEADERVIEW

View File

@ -122,7 +122,11 @@ QVariant AttributeTableModel::headerData(int section, Qt::Orientation orientatio
return role == Qt::DisplayRole ? "No." : QVariant(); return role == Qt::DisplayRole ? "No." : QVariant();
else else
{ {
return m_displayField.value(section - 1).displayName; QString headerText = m_displayField.value(section - 1).displayName;
if(!m_displayField.value(section - 1).dataType.isEmpty())
headerText = headerText + "\n" + m_displayField.value(section - 1).dataType;
return headerText;
} }
} }
return QAbstractTableModel::headerData(section, orientation, role); return QAbstractTableModel::headerData(section, orientation, role);
@ -144,7 +148,7 @@ Qt::ItemFlags AttributeTableModel::flags(const QModelIndex &index) const
QString text = numberIndex.data(Qt::DisplayRole).toString(); QString text = numberIndex.data(Qt::DisplayRole).toString();
Qt::ItemFlags flags = QAbstractTableModel::flags(index); Qt::ItemFlags flags = QAbstractTableModel::flags(index);
if (index.column() != 0 || !text.contains("-")) //行号列不能编辑 if (index.column() != 0 && !text.contains("-")) //行号列和处于删除状态的item不能编辑
flags = flags | Qt::ItemIsEditable; flags = flags | Qt::ItemIsEditable;
return flags; return flags;
} }
@ -154,26 +158,31 @@ void AttributeTableModel::iniDisplayField()
FieldInfo field1; FieldInfo field1;
field1.originalName = "attribute"; field1.originalName = "attribute";
field1.displayName = QString::fromWCharArray(L"属性类别"); field1.displayName = QString::fromWCharArray(L"属性类别");
field1.dataType = "character varying(128)";
m_displayField.append(field1); m_displayField.append(field1);
FieldInfo field2; FieldInfo field2;
field2.originalName = "attribute_name"; field2.originalName = "attribute_name";
field2.displayName = QString::fromWCharArray(L"属性名称"); field2.displayName = QString::fromWCharArray(L"属性名称");
field2.dataType = "character varying(64)";
m_displayField.append(field2); m_displayField.append(field2);
FieldInfo field3; FieldInfo field3;
field3.originalName = "data_type_id"; field3.originalName = "data_type_id";
field3.displayName = QString::fromWCharArray(L"数据类型"); field3.displayName = QString::fromWCharArray(L"数据类型");
field3.dataType = "bigint";
m_displayField.append(field3); m_displayField.append(field3);
FieldInfo field4; FieldInfo field4;
field4.originalName = "length_precision"; field4.originalName = "length_precision";
field4.displayName = QString::fromWCharArray(L"数据精度"); field4.displayName = QString::fromWCharArray(L"数据精度");
field4.dataType = "integer";
m_displayField.append(field4); m_displayField.append(field4);
FieldInfo field5; FieldInfo field5;
field5.originalName = "default_value"; field5.originalName = "default_value";
field5.displayName = QString::fromWCharArray(L"默认值"); field5.displayName = QString::fromWCharArray(L"默认值");
field5.dataType = "character varying(64)";
m_displayField.append(field5); m_displayField.append(field5);
} }

View File

@ -1,7 +1,9 @@
#include "attributeView.h" #include "attributeView.h"
#include "attributeTableDelegate.h" #include "attributeTableDelegate.h"
#include "multiLineHeaderView.h"
#include <QHeaderView> #include <QHeaderView>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QTimer>
AttributeView::AttributeView(const ModelAttributeGroup& modelAttributeGroup, QWidget* parent, const QString& connection, const QString& tableName) AttributeView::AttributeView(const ModelAttributeGroup& modelAttributeGroup, QWidget* parent, const QString& connection, const QString& tableName)
: QWidget(parent) : QWidget(parent)
@ -11,7 +13,7 @@ AttributeView::AttributeView(const ModelAttributeGroup& modelAttributeGroup, QWi
{ {
m_tableView = new QTableView(this); m_tableView = new QTableView(this);
m_tableView->verticalHeader()->setVisible(false); m_tableView->verticalHeader()->setVisible(false);
m_tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); //m_tableView->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
m_attributeTableModel = new AttributeTableModel(m_modelAttributeGroup, this, m_connection, m_attributeTable); m_attributeTableModel = new AttributeTableModel(m_modelAttributeGroup, this, m_connection, m_attributeTable);
m_tableView->setModel(m_attributeTableModel); m_tableView->setModel(m_attributeTableModel);
@ -19,6 +21,29 @@ AttributeView::AttributeView(const ModelAttributeGroup& modelAttributeGroup, QWi
AttributeTableDelegate* delegate = new AttributeTableDelegate(m_tableView, m_tableView); AttributeTableDelegate* delegate = new AttributeTableDelegate(m_tableView, m_tableView);
m_tableView->setItemDelegate(delegate); m_tableView->setItemDelegate(delegate);
//自定义表头
m_multiLinHeader = new MultiLineHeaderView(Qt::Horizontal, this);
QColor bg(246, 246, 246);
QColor border(228, 228, 228);
m_multiLinHeader->setBackgroundColor(bg);
m_multiLinHeader->setBorderColor(border);
//主标题加粗展示
for(int i =0; i < m_attributeTableModel->columnCount(); i++)
{
HeaderLineStyle mainTitleStyle;
mainTitleStyle.font.setBold(true);
m_multiLinHeader->setSectionLineStyle(i, 0, mainTitleStyle);
HeaderLineStyle subTitleStyle;
//subTitleStyle.font.setPointSize(8);
m_multiLinHeader->setSectionLineStyle(i, 1, subTitleStyle);
}
m_tableView->setHorizontalHeader(m_multiLinHeader);
//除了第一列其余列恢复可以手动调整模式
QTimer::singleShot(1000, [=](){
for(int i = 1; i < m_multiLinHeader->count(); i++)
m_multiLinHeader->setSectionResizeMode(i, QHeaderView::Interactive);
});
m_vLayout = new QVBoxLayout(this); m_vLayout = new QVBoxLayout(this);
m_vLayout->setSpacing(0); m_vLayout->setSpacing(0);
m_vLayout->setContentsMargins(0, 0, 0, 0); m_vLayout->setContentsMargins(0, 0, 0, 0);

View File

@ -5,6 +5,7 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
qputenv("QT_WAYLAND_DISABLE_WINDOWDECORATION", "0"); // Wayland 下启用装饰
QApplication a(argc, argv); QApplication a(argc, argv);
LOG_INFO("Application", "------------------------------------------------Application start------------------------------------------------"); LOG_INFO("Application", "------------------------------------------------Application start------------------------------------------------");

View File

@ -99,8 +99,12 @@ void MainWindow::showMessageDialog(MessageDialogType type,const QString& strTitl
} }
m_pMessageDialog->setMessage(type, strTitle, strContent); m_pMessageDialog->setMessage(type, strTitle, strContent);
int nX = this->geometry().x() + (this->width() - m_pMessageDialog->width()) * 0.5; // int nX = this->geometry().x() + (this->width() - m_pMessageDialog->width()) * 0.5;
int nY = this->geometry().y() + (this->height() - m_pMessageDialog->height()) * 0.5; // int nY = this->geometry().y() + (this->height() - m_pMessageDialog->height()) * 0.5;
// m_pMessageDialog->move(nX, nY);
QRect parentFrame = this->frameGeometry(); // 获取父窗口的完整几何信息(包含边框和标题栏),适用于快平台对其
int nX = parentFrame.x() + (parentFrame.width() - m_pMessageDialog->width()) / 2;
int nY = parentFrame.y() + (parentFrame.height() - m_pMessageDialog->height()) / 2;
m_pMessageDialog->move(nX, nY); m_pMessageDialog->move(nX, nY);
//m_pMessageDialog->raise(); //m_pMessageDialog->raise();
// if(type == type_question) // if(type == type_question)
@ -142,8 +146,12 @@ void MainWindow::onActionTrigger_connect()
connect(m_pConnectionDialog, &ConnectionDialog::addConnection, this, &MainWindow::onSIG_addConnection); connect(m_pConnectionDialog, &ConnectionDialog::addConnection, this, &MainWindow::onSIG_addConnection);
} }
int nX = this->geometry().x() + (this->width() - m_pConnectionDialog->width()) * 0.5; /* int nX = this->geometry().x() + (this->width() - m_pConnectionDialog->width()) * 0.5;
int nY = this->geometry().y() + (this->height() - m_pConnectionDialog->height()) * 0.5; int nY = this->geometry().y() + (this->height() - m_pConnectionDialog->height()) * 0.5;
m_pConnectionDialog->move(nX, nY);*/
QRect parentFrame = this->frameGeometry(); // 获取父窗口的完整几何信息(包含边框和标题栏),适用于快平台对其
int nX = parentFrame.x() + (parentFrame.width() - m_pConnectionDialog->width()) / 2;
int nY = parentFrame.y() + (parentFrame.height() - m_pConnectionDialog->height()) / 2;
m_pConnectionDialog->move(nX, nY); m_pConnectionDialog->move(nX, nY);
m_pConnectionDialog->exec(); m_pConnectionDialog->exec();
} }

View File

@ -0,0 +1,104 @@
#include "multiLineHeaderView.h"
#include <QPainter>
MultiLineHeaderView::MultiLineHeaderView(Qt::Orientation orientation, QWidget* parent)
: QHeaderView(orientation, parent)
{
m_linSpacing = 2;
m_bgColor = QColor(Qt::white);
m_borderColor = QColor(Qt::lightGray);
setSectionResizeMode(QHeaderView::ResizeToContents);//根据内容自动调整大小
}
void MultiLineHeaderView::setLineSpacing(int spacing)
{
m_linSpacing = spacing;
}
void MultiLineHeaderView::setBackgroundColor(QColor& color)
{
m_bgColor = color;
}
void MultiLineHeaderView::setBorderColor(QColor& color)
{
m_borderColor = color;
}
void MultiLineHeaderView::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const
{
if(!painter->isActive())
return;
//绘制背景
painter->fillRect(rect, m_bgColor);
//获取文本
QString text = model()->headerData(logicalIndex, orientation()).toString();
QStringList lines = text.split('\n');
//获取当前列的样式
QMap<int, HeaderLineStyle> styles = m_sectionStyles.value(logicalIndex);
//计算总高度并垂直居中
int totalHeight = 0;
QVector<int> lineHeights;
for(int i = 0; i < lines.size(); i++)
{
HeaderLineStyle style = styles.value(i, m_defaultStyle);
QFontMetrics fm(style.font);
lineHeights.append(fm.height());
totalHeight += fm.height() + (i < lines.size() - 1 ? m_linSpacing : 0);
}
int y = rect.y() + (rect.height() - totalHeight) * 0.5;
//逐行绘制文本
for(int i = 0; i < lines.size(); i++)
{
const QString& line = lines.at(i);
HeaderLineStyle style = styles.value(i, m_defaultStyle);
QFontMetrics fm(style.font);
//水平位置
int padding = 10;
int x = rect.x() + padding; //左对齐
if(style.alignment & Qt::AlignRight) //右对齐
x = rect.right() - fm.horizontalAdvance(line) - 4;//'horizontalAdvance'计算文本的横向距离
else if(style.alignment & Qt::AlignHCenter) //水平居中
x = rect.x() + (rect.width() - fm.horizontalAdvance(line)) * 0.5;
//设置字体和颜色
painter->setFont(style.font);
painter->setPen(style.color);
//绘制文本
painter->drawText(x, y + fm.ascent(), line); //绘制文本的基线X轴离文本上方的距离为ascent下方距离为descent
y = y + lineHeights[i] + m_linSpacing;
}
//绘制边框
QPen pen(m_borderColor, 1);
painter->setPen(pen);
QRect adjustRect = rect.adjusted(0, 0, 1, 0);
painter->drawLine(adjustRect.topLeft(), adjustRect.bottomLeft());
painter->drawLine(adjustRect.topRight(), adjustRect.bottomRight());
}
//自动调整行高
QSize MultiLineHeaderView::sectionSizeFromContents(int logicalIndex) const
{
//获取文本
QString text = model()->headerData(logicalIndex, orientation()).toString();
//获取当前列的样式
QMap<int, HeaderLineStyle> styles = m_sectionStyles.value(logicalIndex);
QStringList lines = text.split('\n');
int maxWidth = 0;
int totalHeight = 0;
for(int i = 0; i < lines.size(); i++)
{
HeaderLineStyle style = styles.value(i, m_defaultStyle);
QFontMetrics fm(style.font);
maxWidth = qMax(maxWidth, fm.horizontalAdvance(lines[i]));
totalHeight += fm.height() + (i < lines.size() - 1 ? m_linSpacing : 0);
}
//qDebug() << maxWidth << "," << totalHeight;
return QSize(maxWidth + 20, totalHeight + 4);
}
void MultiLineHeaderView::setSectionLineStyle(int section, int line, const HeaderLineStyle& style)
{
m_sectionStyles[section][line] = style;
updateSection(section);
}

View File

@ -68,12 +68,10 @@ QTabBar::tab:selected
QHeaderView QHeaderView
{ {
background-color: rgb(240, 240, 240); background-color: rgb(250, 250, 250);
} }
QHeaderView::section QHeaderView::section
{ {
height:26px;
background-color: transparent;
} }
QTableView QTableView