2025 July 24 Essay
自定义标题栏
换Titlebar
class CT_CORE_EXPORT TitleBar : public QFrame
{
Q_OBJECT
public:
explicit TitleBar(QString titleName, QWidget *parent = nullptr);
~TitleBar();
static void swapTitleBar(QString titleName, QWidget* wid, bool translucent = true);
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
private:
Ui::TitleBar *ui;
QPoint dragPosition;
};
TitleBar::TitleBar(QString titleName, QWidget *parent) :
QFrame(parent),
ui(new Ui::TitleBar)
{
ui->setupUi(this);
setFixedHeight(30);
ui->label_title->setText(titleName);
connect(ui->pushButton, &QPushButton::clicked, parent, &QWidget::close);
}
TitleBar::~TitleBar()
{
delete ui;
}
void TitleBar::swapTitleBar(QString titleName, QWidget *wid, bool translucent) {
// 去除系统标题栏
wid->setWindowFlags(Qt::FramelessWindowHint);
wid->setAttribute(Qt::WA_TranslucentBackground, translucent);
// 获取 Designer 的主布局(假设是 verticalLayout)
QBoxLayout *originalLayout = qobject_cast<QBoxLayout *>(wid->layout());
if (!originalLayout) {
originalLayout = new QVBoxLayout(wid);
wid->setLayout(originalLayout);
}
// 插入自定义标题栏到顶部
TitleBar *titleBar = new TitleBar(titleName, wid);
originalLayout->setSpacing(0);
originalLayout->insertWidget(0, titleBar);
}
void TitleBar::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton) {
dragPosition = event->globalPos() - parentWidget()->pos();
event->accept();
}
}
void TitleBar::mouseMoveEvent(QMouseEvent *event) {
if (event->buttons() & Qt::LeftButton) {
parentWidget()->move(event->globalPos() - dragPosition);
event->accept();
}
}
实现拖拽功能
去掉标题栏后,mousemoveevent不会自动触发,即使设置了mousetracking。需要点击左键已经才能触发,所以设置hover触发。mousemove函数只响应拖动
class GrayAnalysisDialog : public QDialog
{
Q_OBJECT
public:
explicit GrayAnalysisDialog(vtkSmartPointer<vtkImageData> data, QWidget *parent = nullptr);
~GrayAnalysisDialog();
enum ResizeRegion {
None,
Left, Right, Top, Bottom,
TopLeft, TopRight, BottomLeft, BottomRight
};
ResizeRegion m_Region = None;
bool m_resizing = false;
QPoint m_dragStartPos;
QRect m_startGeometry;
int m_border = 6;
protected:
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *);
bool event(QEvent* event);
ResizeRegion detectRegion(const QPoint& pos);
void updateCursorShape(const QPoint& pos);
void resizeWindow(const QPoint& globalPos);
private:
Ui::GrayAnalysisDialog *ui;
};
GrayAnalysisDialog::GrayAnalysisDialog(vtkSmartPointer<vtkImageData> data, QWidget *parent) :
QDialog(parent),
ui(new Ui::GrayAnalysisDialog)
{
setAttribute(Qt::WA_DeleteOnClose);
this->resize(800, 600);
ui->setupUi(this);
TitleBar::swapTitleBar("灰度分析", this, false);
this->setWindowFlags(Qt::FramelessWindowHint);
this->setAttribute(Qt::WA_TranslucentBackground, false);
setAttribute(Qt::WA_Hover, true);
this->setMouseTracking(true);
}
void GrayAnalysisDialog::mouseMoveEvent(QMouseEvent *event)
{
if (m_resizing) {
resizeWindow(event->globalPos());
}
QDialog::mouseMoveEvent(event);
}
void GrayAnalysisDialog::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
m_Region = detectRegion(event->pos());
if (m_Region != None) {
m_resizing = true;
m_dragStartPos = event->globalPos();
m_startGeometry = geometry();
}
}
QDialog::mousePressEvent(event);
}
void GrayAnalysisDialog::mouseReleaseEvent(QMouseEvent *event)
{
m_resizing = false;
m_Region = None;
QDialog::mouseReleaseEvent(event);
}
bool GrayAnalysisDialog::event(QEvent *event)
{
if (event->type() == QEvent::HoverMove) {
QHoverEvent* hover = static_cast<QHoverEvent*>(event);
updateCursorShape(hover->pos());
}
return QDialog::event(event);
}
GrayAnalysisDialog::ResizeRegion GrayAnalysisDialog::detectRegion(const QPoint &pos)
{
const int x = pos.x();
const int y = pos.y();
const int w = width();
const int h = height();
bool onLeft = x <= m_border;
bool onRight = x >= w - m_border;
bool onTop = y <= m_border;
bool onBottom = y >= h - m_border;
if (onTop && onLeft) return TopLeft;
if (onTop && onRight) return TopRight;
if (onBottom && onLeft) return BottomLeft;
if (onBottom && onRight) return BottomRight;
if (onTop) return Top;
if (onBottom) return Bottom;
if (onLeft) return Left;
if (onRight) return Right;
return None;
}
void GrayAnalysisDialog::updateCursorShape(const QPoint &pos)
{
switch (detectRegion(pos)) {
case Top:
case Bottom:
setCursor(Qt::SizeVerCursor); break;
case Left:
case Right:
setCursor(Qt::SizeHorCursor); break;
case TopLeft:
case BottomRight:
setCursor(Qt::SizeFDiagCursor); break;
case TopRight:
case BottomLeft:
setCursor(Qt::SizeBDiagCursor); break;
default:
setCursor(Qt::ArrowCursor); break;
}
}
void GrayAnalysisDialog::resizeWindow(const QPoint &globalPos)
{
QRect g = m_startGeometry;
QPoint delta = globalPos - m_dragStartPos;
switch (m_Region) {
case Left:
g.setLeft(g.left() + delta.x()); break;
case Right:
g.setRight(g.right() + delta.x()); break;
case Top:
g.setTop(g.top() + delta.y()); break;
case Bottom:
g.setBottom(g.bottom() + delta.y()); break;
case TopLeft:
g.setTopLeft(g.topLeft() + delta); break;
case TopRight:
g.setTopRight(g.topRight() + delta); break;
case BottomLeft:
g.setBottomLeft(g.bottomLeft() + delta); break;
case BottomRight:
g.setBottomRight(g.bottomRight() + delta); break;
default:
return;
}
// 可选:限制最小尺寸
if (g.width() < minimumWidth()) g.setWidth(minimumWidth());
if (g.height() < minimumHeight()) g.setHeight(minimumHeight());
setGeometry(g);
}
在windows系统下,使用NativeEvent()直接实现
win32{
msvc:LIBS += User32.lib
msvc:LIBS += gdi32.lib
}
#include "Windows.h"
#include <windowsx.h>
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
const int borderWidth = 5;
if (eventType == "windows_generic_MSG") {
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_NCHITTEST) {
RECT winRect;
HWND hwnd = (HWND)winId();
GetWindowRect(hwnd, &winRect);
long x = GET_X_LPARAM(msg->lParam);
long y = GET_Y_LPARAM(msg->lParam);
int b = borderWidth;
// 判断四个角
if (x >= winRect.left && x < winRect.left+b &&
y >= winRect.top && y < winRect.top+b) {
*result = HTTOPLEFT; return true;
}
if (x < winRect.right && x >= winRect.right-b &&
y >= winRect.top && y < winRect.top+b) {
*result = HTTOPRIGHT; return true;
}
if (x >= winRect.left && x < winRect.left+b &&
y < winRect.bottom && y >= winRect.bottom-b) {
*result = HTBOTTOMLEFT; return true;
}
if (x < winRect.right && x >= winRect.right-b &&
y < winRect.bottom && y >= winRect.bottom-b) {
*result = HTBOTTOMRIGHT; return true;
}
// 判断四边
if (x >= winRect.left && x < winRect.left+b) {
*result = HTLEFT; return true;
}
if (x < winRect.right && x >= winRect.right-b) {
*result = HTRIGHT; return true;
}
if (y >= winRect.top && y < winRect.top+b) {
*result = HTTOP; return true;
}
if (y < winRect.bottom && y >= winRect.bottom-b) {
*result = HTBOTTOM; return true;
}
}
}
return QMainWindow::nativeEvent(eventType, message, result);
}