init commit
This commit is contained in:
commit
cb33c3b525
25
CMakeLists.txt
Normal file
25
CMakeLists.txt
Normal file
@ -0,0 +1,25 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(checkbox_header_table)
|
||||
|
||||
# 添加以下编译选项
|
||||
if(MSVC)
|
||||
add_compile_options(/utf-8)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets)
|
||||
|
||||
add_executable(checkbox_header_table
|
||||
checkbox_header_table.h
|
||||
checkbox_header_table.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(checkbox_header_table PRIVATE
|
||||
Qt6::Widgets
|
||||
)
|
143
card_list_widget.cpp
Normal file
143
card_list_widget.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
#include "card_list_widget.h"
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
CardItemDelegate::CardItemDelegate(QObject* parent)
|
||||
: QStyledItemDelegate(parent)
|
||||
{
|
||||
}
|
||||
|
||||
void CardItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
// 获取数据
|
||||
CardData data = index.data(Qt::UserRole).value<CardData>();
|
||||
|
||||
// 绘制卡片背景
|
||||
QRect rect = option.rect;
|
||||
rect.adjust(5, 5, -5, -5); // 留出边距
|
||||
|
||||
// 如果被选中,绘制不同的背景色
|
||||
if (option.state & QStyle::State_Selected) {
|
||||
painter->fillRect(rect, QColor(230, 230, 255));
|
||||
} else {
|
||||
painter->fillRect(rect, Qt::white);
|
||||
}
|
||||
|
||||
// 绘制卡片边框
|
||||
painter->setPen(QPen(Qt::lightGray));
|
||||
painter->drawRect(rect);
|
||||
|
||||
// 设置字体
|
||||
QFont nameFont = painter->font();
|
||||
nameFont.setBold(true);
|
||||
nameFont.setPointSize(10);
|
||||
|
||||
QFont normalFont = painter->font();
|
||||
normalFont.setPointSize(9);
|
||||
|
||||
// 计算文本区域
|
||||
int padding = 10;
|
||||
QRect nameRect = rect.adjusted(padding, padding, -padding, 0);
|
||||
nameRect.setHeight(25);
|
||||
|
||||
QRect dateRect = nameRect;
|
||||
dateRect.translate(0, nameRect.height());
|
||||
|
||||
QRect descRect = dateRect;
|
||||
descRect.translate(0, dateRect.height());
|
||||
descRect.setHeight(40);
|
||||
|
||||
// 绘制文本
|
||||
painter->setFont(nameFont);
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawText(nameRect, Qt::AlignLeft | Qt::AlignVCenter, data.name);
|
||||
|
||||
painter->setFont(normalFont);
|
||||
painter->setPen(Qt::darkGray);
|
||||
painter->drawText(dateRect, Qt::AlignLeft | Qt::AlignVCenter, data.date);
|
||||
|
||||
// 绘制描述文本,支持自动换行
|
||||
painter->drawText(descRect, Qt::AlignLeft | Qt::AlignTop | Qt::TextWordWrap,
|
||||
data.description);
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
QSize CardItemDelegate::sizeHint(const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(index);
|
||||
return QSize(300, 100); // 卡片固定大小
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
setWindowTitle(tr("卡片列表示例"));
|
||||
resize(400, 600);
|
||||
|
||||
// 创建布局
|
||||
auto layout = new QVBoxLayout(this);
|
||||
|
||||
// 创建列表控件
|
||||
listWidget = new QListWidget(this);
|
||||
listWidget->setSpacing(5); // 设置卡片间距
|
||||
listWidget->setViewMode(QListView::ListMode);
|
||||
listWidget->setItemDelegate(new CardItemDelegate(listWidget));
|
||||
|
||||
// 设置样式
|
||||
listWidget->setStyleSheet(
|
||||
"QListWidget {"
|
||||
" background-color: #f0f0f0;"
|
||||
" border: none;"
|
||||
"}"
|
||||
"QListWidget::item {"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
"QListWidget::item:selected {"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
);
|
||||
|
||||
layout->addWidget(listWidget);
|
||||
|
||||
// 添加示例数据
|
||||
for (int i = 1; i <= 10; ++i) {
|
||||
CardData data{
|
||||
QString(tr("项目 %1")).arg(i),
|
||||
QDate::currentDate().toString("yyyy-MM-dd"),
|
||||
QString(tr("这是项目 %1 的详细描述信息,可以包含多行文本内容。")).arg(i)
|
||||
};
|
||||
addCardItem(data);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::addCardItem(const CardData& data)
|
||||
{
|
||||
QListWidgetItem* item = new QListWidgetItem(listWidget);
|
||||
item->setData(Qt::UserRole, QVariant::fromValue(data));
|
||||
listWidget->addItem(item);
|
||||
}
|
||||
|
||||
// 注册自定义数据类型
|
||||
Q_DECLARE_METATYPE(CardData)
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// 设置编码和字体
|
||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||
QFont font("Microsoft YaHei");
|
||||
app.setFont(font);
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
|
||||
return app.exec();
|
||||
}
|
38
card_list_widget.h
Normal file
38
card_list_widget.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef CARD_LIST_WIDGET_H
|
||||
#define CARD_LIST_WIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QListWidget>
|
||||
#include <QStyledItemDelegate>
|
||||
|
||||
// 卡片数据结构
|
||||
struct CardData {
|
||||
QString name;
|
||||
QString date;
|
||||
QString description;
|
||||
};
|
||||
|
||||
// 自定义委托类来绘制卡片样式
|
||||
class CardItemDelegate : public QStyledItemDelegate {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CardItemDelegate(QObject* parent = nullptr);
|
||||
|
||||
void paint(QPainter* painter, const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const override;
|
||||
QSize sizeHint(const QStyleOptionViewItem& option,
|
||||
const QModelIndex& index) const override;
|
||||
};
|
||||
|
||||
// 主窗口类
|
||||
class MainWindow : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = nullptr);
|
||||
|
||||
private:
|
||||
QListWidget* listWidget;
|
||||
void addCardItem(const CardData& data);
|
||||
};
|
||||
|
||||
#endif // CARD_LIST_WIDGET_H
|
264
card_list_widget.py
Normal file
264
card_list_widget.py
Normal file
@ -0,0 +1,264 @@
|
||||
from PySide6.QtWidgets import (QApplication, QWidget, QListWidget, QListWidgetItem,
|
||||
QStyledItemDelegate, QVBoxLayout, QStyle, QMenu)
|
||||
from PySide6.QtCore import Qt, QRect, QSize
|
||||
from PySide6.QtGui import QPainter, QPen, QColor, QFont, QPainterPath, QLinearGradient
|
||||
import subprocess
|
||||
import os
|
||||
from datetime import date
|
||||
import sys
|
||||
|
||||
class CardData:
|
||||
"""卡片数据结构"""
|
||||
def __init__(self, name: str, date: str, description: str):
|
||||
self.name = name
|
||||
self.date = date
|
||||
self.description = description
|
||||
self.activated = False # 添加激活状态标志
|
||||
|
||||
class CardItemDelegate(QStyledItemDelegate):
|
||||
"""自定义委托类来绘制卡片样式"""
|
||||
def paint(self, painter: QPainter, option, index):
|
||||
painter.setRenderHint(QPainter.Antialiasing) # 启用抗锯齿
|
||||
painter.save()
|
||||
|
||||
# 获取数据
|
||||
item = index.data(Qt.UserRole)
|
||||
if not isinstance(item, CardData):
|
||||
print(f"Warning: Invalid data type: {type(item)}")
|
||||
return
|
||||
|
||||
# 绘制卡片背景
|
||||
rect = option.rect
|
||||
rect.adjust(8, 4, -8, -4) # 调整边距
|
||||
|
||||
# 创建圆角路径
|
||||
path = QPainterPath()
|
||||
path.addRoundedRect(rect, 8, 8)
|
||||
|
||||
# 绘制阴影
|
||||
shadow_color = QColor(0, 0, 0, 30)
|
||||
for i in range(5):
|
||||
shadow_rect = rect.adjusted(0, i, 0, i)
|
||||
shadow_path = QPainterPath()
|
||||
shadow_path.addRoundedRect(shadow_rect, 8, 8)
|
||||
painter.fillPath(shadow_path, shadow_color)
|
||||
|
||||
# 绘制卡片背景
|
||||
if item.activated: # 激活状态
|
||||
gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
|
||||
gradient.setColorAt(0, QColor(40, 70, 45))
|
||||
gradient.setColorAt(1, QColor(45, 80, 50))
|
||||
painter.fillPath(path, gradient)
|
||||
painter.setPen(QPen(QColor(60, 180, 90), 2))
|
||||
elif option.state & QStyle.State_Selected:
|
||||
gradient = QLinearGradient(rect.topLeft(), rect.bottomLeft())
|
||||
gradient.setColorAt(0, QColor(45, 45, 55))
|
||||
gradient.setColorAt(1, QColor(55, 55, 65))
|
||||
painter.fillPath(path, gradient)
|
||||
painter.setPen(QPen(QColor(70, 130, 180), 2))
|
||||
else:
|
||||
painter.fillPath(path, QColor(35, 35, 40)) # 深色背景
|
||||
painter.setPen(QPen(QColor(60, 60, 65)))
|
||||
|
||||
painter.drawPath(path)
|
||||
|
||||
# 设置字体
|
||||
name_font = QFont("Microsoft YaHei", 10)
|
||||
name_font.setBold(True)
|
||||
|
||||
normal_font = QFont("Microsoft YaHei", 9)
|
||||
|
||||
# 计算文本区域
|
||||
padding = 15
|
||||
name_rect = rect.adjusted(padding, padding, -padding, 0)
|
||||
name_rect.setHeight(25)
|
||||
|
||||
date_rect = QRect(name_rect)
|
||||
date_rect.translate(0, name_rect.height())
|
||||
|
||||
desc_rect = QRect(date_rect)
|
||||
desc_rect.translate(0, date_rect.height())
|
||||
desc_rect.setHeight(40)
|
||||
|
||||
# 绘制文本
|
||||
painter.setFont(name_font)
|
||||
painter.setPen(Qt.white) # 白色文字
|
||||
painter.drawText(name_rect, Qt.AlignLeft | Qt.AlignVCenter, item.name)
|
||||
|
||||
painter.setFont(normal_font)
|
||||
painter.setPen(QColor(180, 180, 180)) # 浅灰色文字
|
||||
painter.drawText(date_rect, Qt.AlignLeft | Qt.AlignVCenter, item.date)
|
||||
|
||||
painter.setPen(QColor(160, 160, 160)) # 描述文字颜色
|
||||
painter.drawText(desc_rect, Qt.AlignLeft | Qt.AlignTop | Qt.TextWordWrap,
|
||||
item.description)
|
||||
|
||||
painter.restore()
|
||||
|
||||
def sizeHint(self, option, index):
|
||||
return QSize(380, 130) # 略微增加高度
|
||||
|
||||
class MainWindow(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("卡片列表示例")
|
||||
self.resize(400, 600)
|
||||
|
||||
# 设置窗口背景色
|
||||
self.setStyleSheet("background-color: #1e1e1e;")
|
||||
|
||||
# 创建布局
|
||||
layout = QVBoxLayout(self)
|
||||
layout.setContentsMargins(10, 10, 10, 10)
|
||||
layout.setSpacing(0)
|
||||
|
||||
# 创建列表控件
|
||||
self.list_widget = QListWidget(self)
|
||||
self.list_widget.setSpacing(10) # 增加卡片间距
|
||||
self.list_widget.setResizeMode(QListWidget.Adjust)
|
||||
self.list_widget.setUniformItemSizes(False)
|
||||
self.list_widget.setViewMode(QListWidget.ListMode)
|
||||
self.list_widget.setVerticalScrollMode(QListWidget.ScrollPerPixel)
|
||||
self.list_widget.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
|
||||
# 设置委托
|
||||
delegate = CardItemDelegate(self.list_widget)
|
||||
self.list_widget.setItemDelegate(delegate)
|
||||
|
||||
# 设置样式
|
||||
self.list_widget.setStyleSheet("""
|
||||
QListWidget {
|
||||
background-color: #1e1e1e;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
QListWidget::item {
|
||||
background-color: transparent;
|
||||
padding: 4px;
|
||||
}
|
||||
QListWidget::item:selected {
|
||||
background-color: transparent;
|
||||
}
|
||||
QScrollBar:vertical {
|
||||
border: none;
|
||||
background: #1e1e1e;
|
||||
width: 8px;
|
||||
margin: 0px;
|
||||
}
|
||||
QScrollBar::handle:vertical {
|
||||
background: #404040;
|
||||
min-height: 20px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
|
||||
background: none;
|
||||
}
|
||||
""")
|
||||
|
||||
layout.addWidget(self.list_widget)
|
||||
|
||||
# 添加示例数据
|
||||
for i in range(1, 11):
|
||||
data = CardData(
|
||||
name=f"项目 {i}",
|
||||
date=date.today().strftime("%Y-%m-%d"),
|
||||
description=f"这是项目 {i} 的详细描述信息,可以包含多行文本内容。这是一个较长的描述,用于测试换行效果。"
|
||||
)
|
||||
self.add_card_item(data)
|
||||
|
||||
# 连接信号
|
||||
self.list_widget.itemDoubleClicked.connect(self.on_item_double_clicked)
|
||||
self.list_widget.customContextMenuRequested.connect(self.show_context_menu)
|
||||
self.list_widget.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||
|
||||
def add_card_item(self, data: CardData):
|
||||
"""添加卡片项目"""
|
||||
item = QListWidgetItem(self.list_widget)
|
||||
item.setData(Qt.UserRole, data)
|
||||
# 设置item大小
|
||||
item.setSizeHint(QSize(380, 120))
|
||||
# 设置item可选
|
||||
item.setFlags(Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable)
|
||||
|
||||
def on_item_double_clicked(self, item):
|
||||
"""双击处理"""
|
||||
data = item.data(Qt.UserRole)
|
||||
if isinstance(data, CardData):
|
||||
data.activated = not data.activated # 切换激活状态
|
||||
self.list_widget.viewport().update() # 刷新视图
|
||||
|
||||
def show_context_menu(self, position):
|
||||
"""显示右键菜单"""
|
||||
item = self.list_widget.itemAt(position)
|
||||
if not item:
|
||||
return
|
||||
|
||||
menu = QMenu(self)
|
||||
|
||||
# 创建动作
|
||||
send_action = menu.addAction("发送到设备")
|
||||
edit_action = menu.addAction("修改")
|
||||
delete_action = menu.addAction("删除")
|
||||
show_in_explorer_action = menu.addAction("在资源管理器中显示")
|
||||
|
||||
# 显示菜单并获取选择的动作
|
||||
action = menu.exec(self.list_widget.viewport().mapToGlobal(position))
|
||||
|
||||
if not action:
|
||||
return
|
||||
|
||||
# 处理菜单动作
|
||||
if action == send_action:
|
||||
self.send_to_device(item)
|
||||
elif action == edit_action:
|
||||
self.edit_item(item)
|
||||
elif action == delete_action:
|
||||
self.delete_item(item)
|
||||
elif action == show_in_explorer_action:
|
||||
self.show_in_explorer(item)
|
||||
|
||||
def send_to_device(self, item):
|
||||
"""发送到设备"""
|
||||
data = item.data(Qt.UserRole)
|
||||
print(f"发送到设备: {data.name}")
|
||||
# TODO: 实现发送到设备的具体逻辑
|
||||
|
||||
def edit_item(self, item):
|
||||
"""编辑项目"""
|
||||
data = item.data(Qt.UserRole)
|
||||
print(f"编辑项目: {data.name}")
|
||||
# TODO: 实现编辑对话框
|
||||
|
||||
def delete_item(self, item):
|
||||
"""删除项目"""
|
||||
row = self.list_widget.row(item)
|
||||
self.list_widget.takeItem(row)
|
||||
|
||||
def show_in_explorer(self, item):
|
||||
"""在资源管理器中显示"""
|
||||
data = item.data(Qt.UserRole)
|
||||
# 这里假设每个项目都有一个关联的文件路径
|
||||
# TODO: 需要在CardData中添加文件路径属性
|
||||
file_path = os.path.abspath(".") # 示例使用当前目录
|
||||
if os.name == 'nt': # Windows
|
||||
subprocess.run(['explorer', '/select,', file_path])
|
||||
elif os.name == 'posix': # macOS 和 Linux
|
||||
if sys.platform == 'darwin': # macOS
|
||||
subprocess.run(['open', '-R', file_path])
|
||||
else: # Linux
|
||||
subprocess.run(['xdg-open', os.path.dirname(file_path)])
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
|
||||
# 设置默认字体
|
||||
font = QFont("Microsoft YaHei", 9)
|
||||
app.setFont(font)
|
||||
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
|
||||
sys.exit(app.exec())
|
124
checkbox_header_table.cpp
Normal file
124
checkbox_header_table.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#pragma execution_character_set("utf-8")
|
||||
|
||||
#include "checkbox_header_table.h"
|
||||
#include <QPainter>
|
||||
#include <QApplication>
|
||||
#include <QTextCodec>
|
||||
|
||||
CheckBoxHeader::CheckBoxHeader(Qt::Orientation orientation, QWidget* parent)
|
||||
: QHeaderView(orientation, parent)
|
||||
, isChecked(false)
|
||||
{
|
||||
setSectionsClickable(true);
|
||||
connect(this, &QHeaderView::sectionClicked, this, &CheckBoxHeader::handleSectionClicked);
|
||||
}
|
||||
|
||||
void CheckBoxHeader::paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const
|
||||
{
|
||||
painter->save();
|
||||
|
||||
if (logicalIndex == 0) {
|
||||
const int checkboxSize = 15;
|
||||
checkboxRect = rect;
|
||||
|
||||
// 计算复选框位置
|
||||
int x = rect.x() + 5; // 从左边留出5像素的间距
|
||||
int y = rect.y() + (rect.height() - checkboxSize) / 2;
|
||||
|
||||
// 绘制复选框
|
||||
painter->setPen(Qt::black);
|
||||
painter->drawRect(x, y, checkboxSize, checkboxSize);
|
||||
|
||||
if (isChecked) {
|
||||
painter->drawLine(x + 3, y + 7, x + 6, y + 10);
|
||||
painter->drawLine(x + 6, y + 10, x + 12, y + 4);
|
||||
}
|
||||
|
||||
// 绘制文字
|
||||
QRect textRect = rect.adjusted(checkboxSize + 10, 0, 0, 0);
|
||||
painter->drawText(textRect, Qt::AlignVCenter, tr("选择"));
|
||||
} else {
|
||||
QHeaderView::paintSection(painter, rect, logicalIndex);
|
||||
}
|
||||
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
void CheckBoxHeader::handleSectionClicked(int logicalIndex)
|
||||
{
|
||||
if (logicalIndex == 0 && !checkboxRect.isNull()) {
|
||||
isChecked = !isChecked;
|
||||
emit checkBoxClicked(isChecked);
|
||||
updateSection(0);
|
||||
}
|
||||
}
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
{
|
||||
setWindowTitle(tr("表头复选框示例"));
|
||||
resize(400, 300);
|
||||
|
||||
// 创建表格
|
||||
table = new QTableWidget(5, 3, this);
|
||||
setCentralWidget(table);
|
||||
|
||||
// 设置表头
|
||||
auto header = new CheckBoxHeader(Qt::Horizontal, table);
|
||||
table->setHorizontalHeader(header);
|
||||
connect(header, &CheckBoxHeader::checkBoxClicked,
|
||||
this, &MainWindow::onHeaderCheckBoxClicked);
|
||||
|
||||
// 设置表头标题
|
||||
QStringList headers;
|
||||
headers << tr("选择") << tr("列1") << tr("列2");
|
||||
table->setHorizontalHeaderLabels(headers);
|
||||
|
||||
// 调整列宽
|
||||
table->horizontalHeader()->setStretchLastSection(true);
|
||||
table->horizontalHeader()->resizeSection(0, 80);
|
||||
|
||||
// 调整表格样式
|
||||
table->setShowGrid(true);
|
||||
table->setAlternatingRowColors(true);
|
||||
|
||||
// 填充表格数据
|
||||
for (int row = 0; row < 5; ++row) {
|
||||
// 添加复选框
|
||||
auto checkboxItem = new QTableWidgetItem();
|
||||
checkboxItem->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
||||
checkboxItem->setCheckState(Qt::Unchecked);
|
||||
table->setItem(row, 0, checkboxItem);
|
||||
|
||||
// 添加其他数据
|
||||
table->setItem(row, 1, new QTableWidgetItem(
|
||||
QString(tr("数据 %1-1")).arg(row + 1)));
|
||||
table->setItem(row, 2, new QTableWidgetItem(
|
||||
QString(tr("数据 %1-2")).arg(row + 1)));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::onHeaderCheckBoxClicked(bool checked)
|
||||
{
|
||||
for (int row = 0; row < table->rowCount(); ++row) {
|
||||
if (QTableWidgetItem* item = table->item(row, 0)) {
|
||||
item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication app(argc, argv);
|
||||
|
||||
// 设置编码
|
||||
QTextCodec::setCodecForLocale(QTextCodec::codecForName("UTF-8"));
|
||||
|
||||
// 设置默认字体
|
||||
QFont font("Microsoft YaHei"); // 使用微软雅黑字体
|
||||
app.setFont(font);
|
||||
|
||||
MainWindow window;
|
||||
window.show();
|
||||
return app.exec();
|
||||
}
|
41
checkbox_header_table.h
Normal file
41
checkbox_header_table.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef CHECKBOX_HEADER_TABLE_H
|
||||
#define CHECKBOX_HEADER_TABLE_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QTableWidget>
|
||||
#include <QHeaderView>
|
||||
|
||||
class CheckBoxHeader : public QHeaderView {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CheckBoxHeader(Qt::Orientation orientation, QWidget* parent = nullptr);
|
||||
|
||||
signals:
|
||||
void checkBoxClicked(bool checked);
|
||||
|
||||
protected:
|
||||
void paintSection(QPainter* painter, const QRect& rect, int logicalIndex) const override;
|
||||
|
||||
private slots:
|
||||
void handleSectionClicked(int logicalIndex);
|
||||
|
||||
private:
|
||||
bool isChecked;
|
||||
mutable QRect checkboxRect;
|
||||
};
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget* parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void onHeaderCheckBoxClicked(bool checked);
|
||||
|
||||
private:
|
||||
QTableWidget* table;
|
||||
};
|
||||
|
||||
#endif // CHECKBOX_HEADER_TABLE_H
|
100
checkbox_header_table.py
Normal file
100
checkbox_header_table.py
Normal file
@ -0,0 +1,100 @@
|
||||
from PySide6.QtWidgets import (QApplication, QMainWindow, QTableWidget,
|
||||
QTableWidgetItem, QHeaderView)
|
||||
from PySide6.QtCore import Qt, Signal
|
||||
from PySide6.QtGui import QPainter
|
||||
import sys
|
||||
|
||||
class CheckBoxHeader(QHeaderView):
|
||||
checkbox_clicked = Signal(bool) # 创建信号用于传递复选框状态
|
||||
|
||||
def __init__(self, orientation, parent=None):
|
||||
super().__init__(orientation, parent)
|
||||
self.is_checked = False
|
||||
self.checkbox_rect = None
|
||||
self.setSectionsClickable(True)
|
||||
self.sectionClicked.connect(self.handle_section_clicked)
|
||||
|
||||
def paintSection(self, painter: QPainter, rect, logical_index):
|
||||
painter.save()
|
||||
|
||||
if logical_index == 0: # 在第一列绘制复选框
|
||||
checkbox_size = 15
|
||||
self.checkbox_rect = rect
|
||||
|
||||
# 计算复选框位置,稍微向左偏移
|
||||
x = rect.x() + 5 # 从左边留出5像素的间距
|
||||
y = rect.y() + (rect.height() - checkbox_size) // 2
|
||||
|
||||
# 绘制复选框
|
||||
painter.setPen(Qt.black)
|
||||
painter.drawRect(x, y, checkbox_size, checkbox_size)
|
||||
|
||||
if self.is_checked:
|
||||
painter.drawLine(x + 3, y + 7, x + 6, y + 10)
|
||||
painter.drawLine(x + 6, y + 10, x + 12, y + 4)
|
||||
|
||||
# 绘制文字
|
||||
text_rect = rect.adjusted(checkbox_size + 10, 0, 0, 0) # 文字位置在复选框右侧
|
||||
painter.drawText(text_rect, Qt.AlignVCenter, "选择")
|
||||
else:
|
||||
# 其他列正常绘制
|
||||
super().paintSection(painter, rect, logical_index)
|
||||
|
||||
painter.restore()
|
||||
|
||||
def handle_section_clicked(self, logical_index):
|
||||
if logical_index == 0 and self.checkbox_rect:
|
||||
self.is_checked = not self.is_checked
|
||||
self.checkbox_clicked.emit(self.is_checked)
|
||||
self.updateSection(0)
|
||||
|
||||
class MainWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setWindowTitle("表头复选框示例")
|
||||
self.resize(400, 300)
|
||||
|
||||
# 创建表格
|
||||
self.table = QTableWidget(5, 3)
|
||||
self.setCentralWidget(self.table)
|
||||
|
||||
# 设置表头
|
||||
header = CheckBoxHeader(Qt.Horizontal, self.table)
|
||||
self.table.setHorizontalHeader(header)
|
||||
header.checkbox_clicked.connect(self.on_header_checkbox_clicked)
|
||||
|
||||
# 设置表头标题
|
||||
self.table.setHorizontalHeaderLabels(["选择", "列1", "列2"])
|
||||
|
||||
# 调整列宽
|
||||
self.table.horizontalHeader().setStretchLastSection(True) # 最后一列自动拉伸
|
||||
self.table.horizontalHeader().resizeSection(0, 80) # 设置第一列宽度为80像素
|
||||
|
||||
# 调整表格样式
|
||||
self.table.setShowGrid(True) # 显示网格线
|
||||
self.table.setAlternatingRowColors(True) # 交替行颜色
|
||||
|
||||
# 填充表格数据
|
||||
for row in range(5):
|
||||
# 添加复选框
|
||||
checkbox_item = QTableWidgetItem()
|
||||
checkbox_item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
|
||||
checkbox_item.setCheckState(Qt.Unchecked)
|
||||
self.table.setItem(row, 0, checkbox_item)
|
||||
|
||||
# 添加其他数据
|
||||
self.table.setItem(row, 1, QTableWidgetItem(f"数据 {row+1}-1"))
|
||||
self.table.setItem(row, 2, QTableWidgetItem(f"数据 {row+1}-2"))
|
||||
|
||||
def on_header_checkbox_clicked(self, checked):
|
||||
# 处理表头复选框点击事件
|
||||
for row in range(self.table.rowCount()):
|
||||
item = self.table.item(row, 0)
|
||||
if item:
|
||||
item.setCheckState(Qt.Checked if checked else Qt.Unchecked)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
window = MainWindow()
|
||||
window.show()
|
||||
sys.exit(app.exec())
|
Loading…
Reference in New Issue
Block a user