最近在用Qt做一个无边框界面,查找诸多资料之后,终于找到了一个很好的办法解决Qt无边框出现的诸多问题。
问题1:Qt去掉边框之后就没有停靠功能,也没有右上角的缩放关闭等功能,而且边框也没有,主界面是纯白色,这就需要添加上这些基本功能。
1.界面还需要添加“顶端”,这个顶端可以提供一些工具栏的按钮,还提供拖动的功能。
2.界面边框添加阴影或者线,
Qt如果做成无边框界面的话就没有边框停靠的功能,也没有鼠标拖拽功能,这些功能就需要自己写,现在计算一下,没有边框需要添加哪些功能,一是停靠功能,二是鼠标拖拽功能,三是右上角缩放关闭等按钮功能,四是加上边框线,以上功能将通过代码全部写出来。
1.去掉边框,添加阴影
#include <windowsx.h>
#include <windows.h>
#pragma comment (lib,"Dwmapi.lib") //添加阴影
#pragma comment (lib,"user32.lib")
main
{
this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
HWND hwnd = (HWND)this->winId();
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
::SetWindowLong(hwnd, GWL_STYLE, style | WS_MAXIMIZEBOX | WS_THICKFRAME | WS_CAPTION);
const MARGINS shadow = { 1, 1, 1, 1 };//留出一个边框添加阴影
DwmExtendFrameIntoClientArea(HWND(winId()), &shadow);
}
2.添加主窗口线
上面代码实现去掉边框的功能,在主窗口上添加边框阴影效果,这时可以实现paintEvent函数画主边框线,具体代码如下:
void MainWindow::paintEvent(QPaintEvent *e)
{
Q_UNUSED(e);
QPainter painter(this);
//画笔添加边框
painter.setBrush(QColor(130,135,144));
painter.setPen(QColor(130, 135, 144));
painter.drawRect(0, 0, 1, this->height());
painter.drawRect(this->width()-1, 0, 1, this->height());
painter.drawRect(0, this->height()-2, this->width(), 2);
painter.drawRect(0,0,this->width(),1);
}
3.添加拖拽,停靠功能
在case WM_NCHITTEST:去掉一些边框面积,那些面积就不能被鼠标拖拽,其余地方就可以被拖拽。在case WM_GETMINMAXINFO:例子中实现窗口停靠功能,
bool MainWindow::nativeEvent(const QByteArray & eventType, void * message, long * result)
{
if (projectWidget)
{
projectWidget->setWID(effectiveWinId());
projectWidget->handleBim5DEvent(eventType, message, 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();
const int HIT_BORDER = 5;//边框大小
//主窗体
auto comBoxRect = QRect(ui.widget_2->pos() + ui.comboBox->pos(), ui.comboBox->size());
auto userRect = QRect(ui.widget_2->pos()+ui.userBtn->pos(),ui.userBtn->size());
auto setRect = QRect(ui.widget_2->pos() + ui.appInfoSetting->pos(),ui.appInfoSetting->size());
auto minRect = QRect(ui.widget_2->pos() + ui.hideBtn->pos(), ui.hideBtn->size());
auto maxRect = QRect(ui.widget_2->pos() + ui.minMaxBtn->pos(),ui.minMaxBtn->size());
auto closeRect = QRect(ui.widget_2->pos() + ui.closeBtn->pos(),ui.closeBtn->size());
//导航按钮
QRect exitProjectRect, saveProjectRect, updateRect, commitRect, lockRect;
if (navigationWidget)
{
//获取控件的大小在测试时候只有一半,所以乘以sizeRate,还没找到原因
float sizeRate = 1.0;
exitProjectRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getExitProjectPos(),navigationWidget->getExitProjectSize()*sizeRate);
saveProjectRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getSaveProjectPos(),navigationWidget->getSaveProjectSize()*sizeRate);
updateRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getUpdatePos(),navigationWidget->getUpdateSize()*sizeRate);
commitRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getCommitPos(),navigationWidget->getCommitSize()*sizeRate);
lockRect = QRect(ui.navigationWidgetContainer->pos() + navigationWidget->getLockPos(), navigationWidget->getLockSize()*sizeRate);
}
//排除按钮部分
if ((xPos > HIT_BORDER && xPos < (ui.stackedWidget->width() - HIT_BORDER) && yPos >(ui.widget_2->height() + HIT_BORDER) && yPos < (this->height() - HIT_BORDER))//工程界面
|| ui.logoLabel->geometry().contains(xPos,yPos)
|| (!navigationWidget && comBoxRect.contains(xPos, yPos))
|| userRect.contains(xPos, yPos)//用户按钮
|| setRect.contains(xPos, yPos)
|| minRect.contains(xPos, yPos)
|| maxRect.contains(xPos, yPos)
|| closeRect.contains(xPos, yPos)
|| (navigationWidget &&
(exitProjectRect.contains(xPos, yPos)
|| saveProjectRect.contains(xPos,yPos)
|| updateRect.contains(xPos,yPos)
|| commitRect.contains(xPos,yPos)
|| lockRect.contains(xPos,yPos))))
{
return false;
}
if (ui.horizontalLayout_2->geometry().contains(xPos, yPos) && xPos > HIT_BORDER && yPos > HIT_BORDER)
{
*result = HTCAPTION;
return true;
}
//边框缩放
if (xPos > 0 && xPos < HIT_BORDER)
{
*result = HTLEFT;
}
else if (xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0)) {
*result = HTRIGHT;
}
else if (yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOP;
}
else if (yPos > (this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOM;
}
if (xPos > 0 && xPos < HIT_BORDER && yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOPLEFT;
}
else if (xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOPRIGHT;
}
else if (xPos > 0 && xPos < HIT_BORDER && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMLEFT;
}
else if (xPos > (this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMRIGHT;
}
return true;
}
break;
case WM_NCCALCSIZE:
return true;
case WM_GETMINMAXINFO:
{
if (::IsZoomed(msg->hwnd))
{
// 最大化时会超出屏幕,所以填充边框间距
RECT frame = { 0, 0, 0, 0};
AdjustWindowRectEx(&frame, WS_OVERLAPPEDWINDOW, FALSE, 0);
frame.left = abs(frame.left);
frame.top = abs(frame.bottom);
this->setContentsMargins(frame.left-1, frame.top-1, frame.right-1, frame.bottom-1);
ui.minMaxBtn->setIcon(QIcon(":/MainWindow/resource/MainWindow/maxWindow.png"));//图标变换
}
else
{
this->setContentsMargins(0, 0, 0, 0);
ui.minMaxBtn->setIcon(QIcon(":/MainWindow/resource/MainWindow/normalWindow.png"));//图标变换
}
*result = ::DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
return true;
}
break;
}
return QMainWindow::nativeEvent(eventType, message, result);
}