赞
踩
最近工作一个项目需要用QT设计一个UI,看了一下目前主流商业化UI,例如扣扣,微信,网易云音乐…结合个人审美(本人非美术专业,但游戏经验丰富,对人机交互界面有个人看法),目前界面风格都是扁平化,纯色调,简单易懂。下面是网易云音乐的效果,本人比较喜欢科技风,类似《使命召唤》和《钢铁侠》风格交互。
系统的标题栏和按钮太传统,想在自定义标题栏类似于网易云音乐标题栏风格。
本人之前用MFC接触QT后感觉开发效率一个天上一个地上,QT可以说把MFC按在地上摩擦。无论QT还是MFC有优点也有缺点,使用过程会详细介绍。
Qt Creator 4.11.0 Based on Qt 5.14.0 (MSVC 2017, 32 bit)
了解各九宫格的概念
一个窗体可以被划分为上、下、左、右、左上、左下、右上、右下、中间,除了中间部分,其他都需要写程序处理。
在程序中定义Padding 为2,并同时定义枚举类型。
#define PADDING 2
enum Direction { UP=0, DOWN=1, LEFT, RIGHT, LEFTTOP, LEFTBOTTOM, RIGHTBOTTOM, RIGHTTOP, NONE };
this->setWindowFlags(Qt::FramelessWindowHint); //取消标题栏
// 去掉标题栏,去掉工具栏,窗口置顶
setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::WindowStaysOnTopHint);
setWindowOpacity(0.7); //设置窗体透明度
主要使用Qt::FramelessWindowHint。但是设置后窗口无法移动,无法关闭,无法调整大小!查了一下资料,网上大神基本给出2种解决办法:
重写mouseMoveEvent,mousePressEvent,mouseReleaseEvent
MainWindow.h
public:
void region(const QPoint ¤tGlobalPoint); //鼠标的位置,改变光标
protected:
//鼠标按下移动及释放事件
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
private:
QPoint m_movePoint; //鼠标的位置
bool isLeftPressDown; // 判断左键是否按下
Direction dir; // 窗口大小改变时,记录改变方向
MainWindow.cpp
void MainWindow::region(const QPoint ¤tGlobalPoint) { // 获取窗体在屏幕上的位置区域,topLeft为坐上角点,rightButton为右下角点 QRect rect = this->rect(); QPoint topLeft = this->mapToGlobal(rect.topLeft()); //将左上角的(0,0)转化为全局坐标 QPoint rightButton = this->mapToGlobal(rect.bottomRight()); int x = currentGlobalPoint.x(); //当前鼠标的坐标 int y = currentGlobalPoint.y(); if(((topLeft.x() + PADDING >= x) && (topLeft.x() <= x)) && ((topLeft.y() + PADDING >= y) && (topLeft.y() <= y))) { // 左上角 dir = LEFTTOP; this->setCursor(QCursor(Qt::SizeFDiagCursor)); // 设置光标形状 }else if(((x >= rightButton.x() - PADDING) && (x <= rightButton.x())) && ((y >= rightButton.y() - PADDING) && (y <= rightButton.y()))) { // 右下角 dir = RIGHTBOTTOM; this->setCursor(QCursor(Qt::SizeFDiagCursor)); }else if(((x <= topLeft.x() + PADDING) && (x >= topLeft.x())) && ((y >= rightButton.y() - PADDING) && (y <= rightButton.y()))) { //左下角 dir = LEFTBOTTOM; this->setCursor(QCursor(Qt::SizeBDiagCursor)); }else if(((x <= rightButton.x()) && (x >= rightButton.x() - PADDING)) && ((y >= topLeft.y()) && (y <= topLeft.y() + PADDING))) { // 右上角 dir = RIGHTTOP; this->setCursor(QCursor(Qt::SizeBDiagCursor)); }else if((x <= topLeft.x() + PADDING) && (x >= topLeft.x())) { // 左边 dir = LEFT; this->setCursor(QCursor(Qt::SizeHorCursor)); }else if((x <= rightButton.x()) && (x >= rightButton.x() - PADDING)) { // 右边 dir = RIGHT; this->setCursor(QCursor(Qt::SizeHorCursor)); }else if((y >= topLeft.y()) && (y <= topLeft.y() + PADDING)) { // 上边 dir = UP; this->setCursor(QCursor(Qt::SizeVerCursor)); }else if((y <= rightButton.y()) && (y >= rightButton.y() - PADDING)) { // 下边 dir = DOWN; this->setCursor(QCursor(Qt::SizeVerCursor)); }else { // 默认 dir = NONE; this->setCursor(QCursor(Qt::ArrowCursor)); } } //三个鼠标事件的重写 //鼠标按下事件 void MainWindow::mousePressEvent(QMouseEvent *event) { switch(event->button()) { case Qt::LeftButton: isLeftPressDown = true; if(dir != NONE) { this->mouseGrabber(); //返回当前抓取鼠标输入的窗口 } else { m_movePoint = event->globalPos() - this->frameGeometry().topLeft(); //globalPos()鼠标位置,topLeft()窗口左上角的位置 } break; case Qt::RightButton: this->setWindowState(Qt::WindowMinimized); break; default: MainWindow::mousePressEvent(event); } } //鼠标移动事件 void MainWindow::mouseMoveEvent(QMouseEvent *event) { QPoint globalPoint = event->globalPos(); //鼠标全局坐标 QRect rect = this->rect(); //rect == QRect(0,0 1280x720) QPoint topLeft = mapToGlobal(rect.topLeft()); QPoint bottomRight = mapToGlobal(rect.bottomRight()); if (this->windowState() != Qt::WindowMaximized) { if(!isLeftPressDown) //没有按下左键时 { this->region(globalPoint); //窗口大小的改变——判断鼠标位置,改变光标形状 } else { if(dir != NONE) { QRect newRect(topLeft, bottomRight); //定义一个矩形 拖动后最大1000*1618 switch(dir) { case LEFT: if(bottomRight.x() - globalPoint.x() <= this->minimumWidth()) { newRect.setLeft(topLeft.x()); //小于界面的最小宽度时,设置为左上角横坐标为窗口x //只改变左边界 } else { newRect.setLeft(globalPoint.x()); } break; case RIGHT: newRect.setWidth(globalPoint.x() - topLeft.x()); //只能改变右边界 break; case UP: if(bottomRight.y() - globalPoint.y() <= this->minimumHeight()) { newRect.setY(topLeft.y()); } else { newRect.setY(globalPoint.y()); } break; case DOWN: newRect.setHeight(globalPoint.y() - topLeft.y()); break; case LEFTTOP: if(bottomRight.x() - globalPoint.x() <= this->minimumWidth()) { newRect.setX(topLeft.x()); } else { newRect.setX(globalPoint.x()); } if(bottomRight.y() - globalPoint.y() <= this->minimumHeight()) { newRect.setY(topLeft.y()); } else { newRect.setY(globalPoint.y()); } break; case RIGHTTOP: if (globalPoint.x() - topLeft.x() >= this->minimumWidth()) { newRect.setWidth(globalPoint.x() - topLeft.x()); } else { newRect.setWidth(bottomRight.x() - topLeft.x()); } if (bottomRight.y() - globalPoint.y() >= this->minimumHeight()) { newRect.setY(globalPoint.y()); } else { newRect.setY(topLeft.y()); } break; case LEFTBOTTOM: if (bottomRight.x() - globalPoint.x() >= this->minimumWidth()) { newRect.setX(globalPoint.x()); } else { newRect.setX(topLeft.x()); } if (globalPoint.y() - topLeft.y() >= this->minimumHeight()) { newRect.setHeight(globalPoint.y() - topLeft.y()); } else { newRect.setHeight(bottomRight.y() - topLeft.y()); } break; case RIGHTBOTTOM: newRect.setWidth(globalPoint.x() - topLeft.x()); newRect.setHeight(globalPoint.y() - topLeft.y()); break; default: break; } this->setGeometry(newRect); } else { move(event->globalPos() - m_movePoint); //移动窗口 event->accept(); } } } } //鼠标释放事件 void MainWindow::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { isLeftPressDown = false; if (dir != NONE) { this->releaseMouse(); //释放鼠标抓取 this->setCursor(QCursor(Qt::ArrowCursor)); dir = NONE; //热心网友指正 } } }
总结起来:
1)窗体矩形区域要转换成在屏幕上的区域,我采取的方式就是取TopLeft和RightBottom两个点来确定这个区域。
2)鼠标移动要去全局的坐标。
3)region函数中判断坐标区间,然后改变鼠标形状
Qt可以处理windows的消息。重新实现bool winEvent(MSG *message, long *result);QT 5.0之后的需要重新实现bool nativeEvent(const QByteArray &eventType, void *message, long *result);
MainWindow.h
protected:
bool nativeEvent(const QByteArray &eventType, void *message, long *result);
MainWindow.cpp
bool MainWindow::nativeEvent(const QByteArray &eventType, void *message, long *result) { MSG* msg = (MSG*)message; switch(msg->message) { case WM_NCHITTEST: int xPos = GET_X_LPARAM(msg->lParam) - this->frameGeometry().x(); int yPos = GET_Y_LPARAM(msg->lParam) - this->frameGeometry().y(); if(this->childAt(xPos,yPos) == 0) { *result = HTCAPTION; }else{ return false; } if(xPos > 0 && xPos < 8) *result = HTLEFT; if(xPos > (this->width() - 8) && xPos < (this->width() - 0)) *result = HTRIGHT; if(yPos > 0 && yPos < 8) *result = HTTOP; if(yPos > (this->height() - 8) && yPos < (this->height() - 0)) *result = HTBOTTOM; if(xPos > 18 && xPos < 22 && yPos > 18 && yPos < 22) *result = HTTOPLEFT; if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > 18 && yPos < 22) *result = HTTOPRIGHT; if(xPos > 18 && xPos < 22 && yPos > (this->height() - 22) && yPos < (this->height() - 18)) *result = HTBOTTOMLEFT; if(xPos > (this->width() - 22) && xPos < (this->width() - 18) && yPos > (this->height() - 22) && yPos < (this->height() - 18)) *result = HTBOTTOMRIGHT; return true; } return false; }
http://www.cnblogs.com/xufeiyang/p/3313104.html
https://blog.csdn.net/u014789012/article/details/103819195
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。