qt中的QWidget窗口支持窗体绘制,但是不支持窗口标题栏绘制,想要美观的界面,还需要自己去定制,下面我就介绍一种定制窗体的方法
一个窗口无非就3部分,标题栏、窗体和状态栏,接下来我定制的窗口没有状态栏,如果自己想加状态栏的话,照着这个模式自己也可以添加,说白了,窗口定制就是把完整的窗口分3部分定制,而每个部分又都是一个qt窗口
定制窗口效果图如下,根据个人喜好,自己也可以定制不同的效果
如图1所示,这个窗口包含两部分,标题栏和窗体,这两部分其实分别是一个没有标题栏的QWidget,接下来我分别介绍下这两部分
标题栏
构造函数代码如下
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 setAutoFillBackground(true);//自动填充背景色,防止继承父窗口背景色 2 3 setStyleSheet(QStringLiteral("background:blue;"));//背景色 4 5 setFixedHeight(30);//设置高度 看个人喜好 可以做微调 6 7 _p->minimize = new QToolButton(this); 8 9 _p->maximize = new QToolButton(this); 10 11 _p->close = new QToolButton(this);
/// 设置系统按钮图标.
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 QPixmap pix = style()->standardPixmap(QStyle::SP_TitleBarCloseButton); 2 3 _p->close->setIcon(pix); 4 5 _p->maxPix = style()->standardPixmap(QStyle::SP_TitleBarMaxButton); 6 7 _p->maximize->setIcon(_p->maxPix); 8 9 pix = style()->standardPixmap(QStyle::SP_TitleBarMinButton); 10 11 _p->minimize->setIcon(pix); 12 13 _p->restorePix = style()->standardPixmap(QStyle::SP_TitleBarNormalButton); 14 15 _p->minimize->setMinimumHeight(20); 16 17 _p->close->setMinimumHeight(20); 18 19 _p->maximize->setMinimumHeight(20); 20 21 _p->label = new QLabel(this); 22 23 _p->label->setAttribute(Qt::WA_TransparentForMouseEvents, true); //鼠标穿透 24 25 _p->label->setStyleSheet(QStringLiteral(" font-size:12px;\ 26 27 font - weight:Bold")); 28 29 _p->label->setMargin(0); 30 31 SetWindowTitle("title"); 32 33 QHBoxLayout *hbox = new QHBoxLayout; 34 35 hbox->addWidget(_p->label); 36 37 hbox->addWidget(_p->minimize); 38 39 hbox->addWidget(_p->maximize); 40 41 hbox->addWidget(_p->close); 42 43 //_p->maximize->setVisible(false); 44 45 hbox->insertStretch(1, 500); 46 47 hbox->setSpacing(0); 48 49 connect(_p->minimize, &QToolButton::clicked, this, [this]{ 50 51 BaseWidget * widget = qobject_cast(parent()); 52 53 if (widget) 54 55 { 56 57 widget->SetWindowMovePos(widget->pos()); 58 59 emit WindowDockedSignal(); 60 61 } 62 63 }); 64 65 connect(_p->maximize, &QToolButton::clicked, this, &TitleBar::showMaxRestore); 66 67 connect(_p->close, &QToolButton::clicked, this, [this]{emit WindowCloseSignal(_p->label->text()); }); 68 69 hbox->setMargin(1); 70 71 hbox->setSpacing(2); 72 73 setLayout(hbox); 74 75 void TitleBar::showMaxRestore()//最大化或者还原 76 77 { 78 79 if (_p->maxNormal) 80 81 { 82 83 _p->maxNormal = !_p->maxNormal; 84 85 _p->maximize->setIcon(_p->maxPix); 86 87 } 88 89 else 90 91 { 92 93 _p->maxNormal = !_p->maxNormal; 94 95 _p->maximize->setIcon(_p->restorePix); 96 97 } 98 99 emit WindowMaxRestoreSignal(_p->maxNormal); 100 101 } 102 103 void TitleBar::SetWindowTitle(const QString & title)//设置窗口标题 104 105 { 106 107 if (_p) 108 109 { 110 111 _p->label->setText(title); 112 113 } 114 115 } 116 117 void TitleBar::SetWindowMaxable(bool isMax) 118 119 { 120 121 if (_p) 122 123 { 124 125 _p->maxNormal = isMax; 126 127 if (_p->maxNormal) 128 129 { 130 131 _p->maximize->setIcon(_p->maxPix); 132 133 } 134 135 else 136 137 { 138 139 _p->maximize->setIcon(_p->restorePix); 140 141 } 142 143 } 144 145 } 146 147 void TitleBar::mousePressEvent(QMouseEvent * event)//移动窗口 148 149 { 150 151 QPoint mousePos = _p->minimize->mapFromParent(event->pos()); 152 153 if (_p->minimize->rect().contains(mousePos))//如果点击了最小化 则不能移动 154 155 { 156 157 return; 158 159 } 160 161 if (_p->maximize->rect().contains(mousePos))//如果点击了最大化不能移动 162 163 { 164 165 return; 166 167 } 168 169 _p->leftButtonPressed = true; 170 171 _p->startPos = event->globalPos(); 172 173 _p->clickPos = mapToParent(event->pos()); 174 175 } 176 177 void TitleBar::mouseReleaseEvent(QMouseEvent * event) 178 179 { 180 181 _p->leftButtonPressed = false; 182 183 } 184 185 void TitleBar::mouseMoveEvent(QMouseEvent * event) 186 187 { 188 189 if (_p->maxNormal) 190 191 { 192 193 return; 194 195 } 196 197 if (_p->leftButtonPressed) 198 199 { 200 201 parentWidget()->move(event->globalPos() - _p->clickPos);//移动父窗口 202 203 } 204 205 } 206 207 void TitleBar::mouseDoubleClickEvent(QMouseEvent * event) 208 209 { 210 211 showMaxRestore(); 212 213 }
窗体定制
直接上代码
cpp如下
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 setFrameShape(Panel); 2 3 setMouseTracking(true); 4 5 setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Tool);/// 隐藏窗口标题栏. 6 7 setFixedSize(150, 190); 8 9 _p->m_mouse_down = false; 10 11 _p->m_titleBar = new TitleBar(this); 12 13 _p->m_titleBar->installEventFilter(this); 14 15 connect(_p->m_titleBar, &TitleBar::WindowDockedSignal 16 17 , this, [this]{ 18 19 setFixedSize(_p->m_content->size()); 20 21 setMinimumSize(0, 0); 22 23 setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); 24 25 _p->m_titleBar->setVisible(false); 26 27 }); 28 29 connect(_p->m_titleBar, &TitleBar::WindowMaxRestoreSignal 30 31 , this, [this](bool isMax){ 32 33 if (isMax) 34 35 { 36 37 showMaximized(); 38 39 } 40 41 else 42 43 { 44 45 showNormal(); 46 47 } 48 49 }); 50 51 _p->m_content = new QWidget(this); 52 53 QPalette plt = _p->m_content->palette(); 54 55 plt.setColor(QPalette::Window, QColor("#000000")); 56 57 _p->m_content->setPalette(plt);//设置背景色黑色 58 59 _p->m_content->setAutoFillBackground(true); 60 61 _p->m_content->setAttribute(Qt::WA_PaintOnScreen, true); 62 63 QVBoxLayout *vbox = new QVBoxLayout(this); 64 65 vbox->addWidget(_p->m_titleBar); 66 67 vbox->setStretchFactor(_p->m_titleBar, 0); 68 69 vbox->setMargin(0); 70 71 vbox->setSpacing(0); 72 73 QVBoxLayout *layout = new QVBoxLayout(this); 74 75 layout->addWidget(_p->m_content); 76 77 layout->setMargin(0); 78 79 layout->setSpacing(0); 80 81 vbox->addLayout(layout); 82 83 vbox->setStretchFactor(layout, 1); 84 85 TitleBar * BaseWidget::GetTitleBar() const 86 87 { 88 89 if (_p) 90 91 { 92 93 return _p->m_titleBar; 94 95 } 96 97 } 98 99 QWidget * BaseWidget::GetContentWidget() const 100 101 { 102 103 if (_p) 104 105 { 106 107 return _p->m_content; 108 109 } 110 111 } 112 113 BaseWidget::State BaseWidget::GetWindowState() const 114 115 { 116 117 if (_p) 118 119 { 120 121 return _p->state; 122 123 } 124 125 } 126 127 void BaseWidget::SetWindowState(BaseWidget::State state) 128 129 { 130 131 if (_p) 132 133 { 134 135 _p->state = state; 136 137 if (_p->state == _floating) 138 139 { 140 141 _p->m_titleBar->setVisible(true); 142 143 } 144 145 else 146 147 { 148 149 _p->m_titleBar->setVisible(false); 150 151 } 152 153 } 154 155 } 156 157 QPoint BaseWidget::GetWindowFloatPos() const 158 159 { 160 161 if (_p) 162 163 { 164 165 return _p->floatPostion; 166 167 } 168 169 } 170 171 void BaseWidget::SetWindowFloatPos(const QPoint & point) 172 173 { 174 175 if (_p) 176 177 { 178 179 _p->floatPostion = point; 180 181 } 182 183 } 184 185 QPoint BaseWidget::GetWindowMovePos() const 186 187 { 188 189 if (_p) 190 191 { 192 193 return _p->m_restorePos; 194 195 } 196 197 } 198 199 void BaseWidget::SetWindowMovePos(const QPoint & pos) 200 201 { 202 203 if (_p) 204 205 { 206 207 _p->m_restorePos = pos; 208 209 } 210 211 } 212 213 bool BaseWidget::eventFilter(QObject * object, QEvent * event) 214 215 { 216 217 if (object == _p->m_titleBar) 218 219 { 220 221 if (event->type() == QEvent::MouseMove) 222 223 { 224 225 QMouseEvent * mouseEvent = static_cast(event); 226 227 if (mouseEvent && mouseEvent->button() & Qt::LeftButton) 228 229 { 230 231 return true;//不做处理 232 233 } 234 235 } 236 237 } 238 239 return QWidget::eventFilter(object, event); 240 241 } 242 243 void BaseWidget::mousePressEvent(QMouseEvent * event) 244 245 { 246 247 if (event->button() == Qt::LeftButton) 248 249 { 250 251 _p->m_mouse_down = true; 252 253 _p->dragPostion = event->globalPos() - frameGeometry().topLeft(); 254 255 event->accept(); 256 257 } 258 259 } 260 261 void BaseWidget::mouseMoveEvent(QMouseEvent * event) 262 263 { 264 265 if (_p->state != _floating || isMaximized())//如果窗口不是悬浮状态 或者最大化 不允许拖动 266 267 { 268 269 return; 270 271 } 272 273 if (_p->m_mouse_down) 274 275 { 276 277 move(event->globalPos() - _p->dragPostion); 278 279 event->accept(); 280 281 } 282 283 } 284 285 void BaseWidget::mouseReleaseEvent(QMouseEvent * event) 286 287 { 288 289 _p->m_mouse_down = false; 290 291 } 292 293 void BaseWidget::mouseDoubleClickEvent(QMouseEvent * event) 294 295 { 296 297 if (_p->state == _dock) 298 299 { 300 301 _p->state = _floating; 302 303 _p->m_titleBar->setVisible(true); 304 305 setParent(nullptr); 306 307 setWindowFlags(Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::Tool); 308 309 move(GetWindowMovePos()); 310 311 show(); 312 313 } 314 315 }
有如上两部分代码,功能基本可以实现