在这里自定义窗口是通过继承于QFrame,内部分为上下两部分,上半部分就是标题栏,下面是窗口的具体内容。上下两部分通过布局固定位置。最后窗口的各种鼠标拖动,缩放,等操作通过添加鼠标事件来完成一个窗口的常规功能。当然,这个标题栏可以通过布局的改变把它放到任意地方。

下面是实现的代码: 
#pragma once 
#ifndef CUSTOMWIDGET_H_ 
#define CUSTOMWIDGET_H_

#include <QtWidgets/QFrame>

class QToolButton; 
class CustomWidget : public QFrame 
{

Q_OBJECT

public:

explicit CustomWidget();
~CustomWidget();
void setContentWidget(QWidget *contentWidget);
void setTitleInfo(const QString &titleString, const QPixmap &windowIcon);

public slots:

void slotShowSmall();
void slotShowMaxRestore();
void onMoveWindow();

signals:

void moveWindow();

protected:

void mousePressEvent(QMouseEvent *);
void mouseMoveEvent(QMouseEvent *);
void mouseReleaseEvent(QMouseEvent *);
bool nativeEvent(const QByteArray & eventType, void * message, long * result);
void paintEvent(QPaintEvent *);

private:

bool isMax;
bool isPress;
QPoint startPos;
QPoint clickPos;
QWidget *m_pTitleWidget;//顶栏窗体
QWidget *m_pContentWidget;//内容窗体
QPixmap maxPixmap;
QPixmap restorePixmap;
QToolButton *m_pMaxButton;

};

#endif //!CUSTOMWIDGET_H_

customWidget.cpp:

#include "stdafx.h" 
#include "customwidget.h" 
#include <QtWidgets/QLabel> 
#include <QtWidgets/QToolButton> 
#include <QtWidgets/QHBoxLayout> 
#include <QtCore/QEvent> 
#include <Window.h>

static const int TITLE_HEIGHT = 40;//标题栏高度 
static const int FRAME_BORDER = 2;//边框宽度 
CustomWidget::CustomWidget() 
: m_pContentWidget(0) 
//, m_llLocalWinId(0) 
//, m_llRemoteWinId(0)
 
{

this->setWindowFlags(Qt::FramelessWindowHint);
this->setAttribute(Qt::WA_TranslucentBackground);
this->setMouseTracking(true); isMax = false;
isPress = false;
m_pTitleWidget = new QWidget();

}

CustomWidget::~CustomWidget() 

}

void CustomWidget::setContentWidget(QWidget *contentWidget) 
{

if (contentWidget)
{
m_pContentWidget = contentWidget;
m_pContentWidget->move(m_pTitleWidget->rect().bottomLeft());
m_pContentWidget->show();
resize(m_pTitleWidget->width(), m_pTitleWidget->height() + m_pContentWidget->height());
}

}

void CustomWidget::setTitleInfo(const QString &titleString, const QPixmap &windowIcon) 
{

QLabel *logoLabel = new QLabel();
logoLabel->setPixmap(windowIcon);
logoLabel->setFixedSize(16, 16);
logoLabel->setScaledContents(true); QLabel *titleLabel = new QLabel();
titleLabel->setText(titleString);
QFont titleFont = titleLabel->font();
titleFont.setBold(true);
titleLabel->setFont(titleFont);
titleLabel->setObjectName("whiteLabel");
titleLabel->setStyleSheet("color:white;"); QToolButton *minButton = new QToolButton();
connect(minButton, SIGNAL(clicked()), this, SLOT(slotShowSmall()));
m_pMaxButton = new QToolButton();
connect(m_pMaxButton, SIGNAL(clicked()), this, SLOT(slotShowMaxRestore()));
QToolButton *closeButton = new QToolButton();
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
connect(this, SIGNAL(moveWindow()), this, SLOT(onMoveWindow())); QHBoxLayout *titleLayout = new QHBoxLayout();
titleLayout->addWidget(logoLabel);
titleLayout->addWidget(titleLabel);
titleLabel->setContentsMargins(5, 0, 0, 0);
titleLayout->addStretch();
titleLayout->addWidget(minButton, 0, Qt::AlignTop);
titleLayout->addWidget(m_pMaxButton, 0, Qt::AlignTop);
titleLayout->addWidget(closeButton, 0, Qt::AlignTop);
titleLayout->setSpacing(0);
titleLayout->setContentsMargins(5, 0, 0, 0); m_pTitleWidget->setFixedSize(600, TITLE_HEIGHT);
m_pTitleWidget->setLayout(titleLayout);
m_pTitleWidget->installEventFilter(0);
m_pTitleWidget->setAutoFillBackground(true);
QPalette palette;
palette.setColor(QPalette::Background, QColor(31,25,25));
m_pTitleWidget->setPalette(palette);

}

void CustomWidget::slotShowSmall()//最小化 

this->showMinimized(); 
}

void CustomWidget::slotShowMaxRestore()//还原按钮 
{

if (isMax) {
this->showNormal();
m_pMaxButton->setIcon(maxPixmap);
}
else {
this->showMaximized();
m_pMaxButton->setIcon(restorePixmap);
}
isMax = !isMax;

}

void CustomWidget::onMoveWindow() 

//m_pContentWidget->move(m_pTitleWidget->rect().bottomLeft()); 
}

void CustomWidget::mousePressEvent(QMouseEvent *e) 
{

startPos = e->globalPos();
clickPos = e->pos(); if (e->button() == Qt::LeftButton) {
if (e->type() == QEvent::MouseButtonPress) {
isPress = true;
}
else if (e->type() == QEvent::MouseButtonDblClick && e->pos().y() <= TITLE_HEIGHT) {
this->slotShowMaxRestore();
}
}

}

void CustomWidget::mouseMoveEvent(QMouseEvent *e) 
{

if (isMax || !isPress) {
return;
}
this->move(e->globalPos() - clickPos);
emit moveWindow();

}

void CustomWidget::mouseReleaseEvent(QMouseEvent *) 

isPress = false; 
}

bool CustomWidget::nativeEvent(const QByteArray & eventType, void * message, long * result)//实现拖拽边框的效果 
{

Q_UNUSED(eventType);
const int HIT_BORDER = 5;
const MSG *msg = static_cast<MSG*>(message);
if (msg->message == WM_NCHITTEST) {
int xPos = ((int)(short)LOWORD(msg->lParam)) - this->frameGeometry().x();
int yPos = ((int)(short)HIWORD(msg->lParam)) - this->frameGeometry().y();
if (this->childAt(xPos, yPos) == 0) {
*result = HTCAPTION;
}
else {
return false;
}
if (xPos > 0 && xPos < HIT_BORDER) {
*result = HTLEFT;
}
if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0)) {
*result = HTRIGHT;
}
if (yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOP;
}
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;
}
if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos > 0 && yPos < HIT_BORDER) {
*result = HTTOPRIGHT;
}
if (xPos > 0 && xPos < HIT_BORDER && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMLEFT;
}
if (xPos >(this->width() - HIT_BORDER) && xPos < (this->width() - 0) && yPos >(this->height() - HIT_BORDER) && yPos < (this->height() - 0)) {
*result = HTBOTTOMRIGHT;
}
return true;
}
return false;

}

void CustomWidget::paintEvent(QPaintEvent *e) 
{//绘制边框

int border = FRAME_BORDER;
if (this->isMaximized()) {
border = 0;
} QPainter painter(this);
QPainterPath painterPath;
painterPath.setFillRule(Qt::WindingFill);
painterPath.addRect(border, border, this->width() - 2 * border, this->height() - 2 * border);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.fillPath(painterPath, QBrush(Qt::black));
QColor color(200, 200, 200);
for (int i = 0; i<border; i++) {
color.setAlpha((i + 1) * 30);
painter.setPen(color);
painter.drawRect(border - i, border - i, this->width() - (border - i) * 2, this->height() - (border - i) * 2);
} painter.setPen(Qt::NoPen);
painter.setBrush(Qt::black);
// 这里可以在资源中指定一张标题背景图片
//painter.drawPixmap(QRect(border, border, this->width()-2*border, this->height()-2*border), QPixmap(DEFAULT_SKIN));
painter.drawRect(QRect(border, TITLE_HEIGHT, this->width() - 2 * border, this->height() - TITLE_HEIGHT - border));
QFrame::paintEvent(e);


///////////////全文完

http://blog.csdn.net/u011915578/article/details/46924151

QT自定义窗口(模拟MainWindow)的更多相关文章

  1. QT自定义窗口

    qt 中允许自定义窗口控件,使之满足特殊要求, (1)可以修改其显示,自行绘制 (2)可以动态显示 (3)可以添加事件,支持鼠标和键盘操作 自定义控件可以直接在QtDesigner里使用,可以直接加到 ...

  2. Qt自定义窗口部件

    QtDesigner自定义窗口部件有两种方法:改进法(promotion)和插件法(plugin)   改进法   1.改进法之前,要先写好子类化QSpinBox后的HexspinBox.h和Hexs ...

  3. qt 自定义窗口绘制正弦曲线

    circlewidget.h #ifndef CIRCLAWIDGET_H #define CIRCLAWIDGET_H #include <QFrame> #include<QVe ...

  4. qt 自定义窗口显示鼠标划过的轨迹

    鼠标事件分为四种: 1.按下 2.抬起 3.移动 4.双击 鼠标事件继承与QWidget void mouseDoubleClickEvent(QMouseEvent *event) void mou ...

  5. QT笔记之自定义窗口拖拽移动

    1.QT自定义标题栏,拖拽标题栏移动窗口(只能拖拽标题,其他位置无法拖拽) 方法一: 转载:http://blog.sina.com.cn/s/blog_4ba5b45e0102e83h.html . ...

  6. Qt入门(19)——自定义窗口部件

    我们介绍可以画自己的第一个自定义窗口部件.我们也加入了一个有用的键盘接口.我们添加了一个槽:setRange().        void setRange( int minVal, int maxV ...

  7. WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)

    WPF 自定义窗口样式有多种方式,不过基本核心实现都是在修改 Win32 窗口样式.然而,Windows 上的应用就应该有 Windows 应用的样子嘛,在保证自定义的同时也能与其他窗口样式保持一致当 ...

  8. QT5每日一学(二)编写QT多窗口程序

    一.添加主窗口 1.首先打开Qt Creator,新建Qt Widgets Application,项目名称设置为windows,在类信息界面保持基类为QMainWindow.类名为MainWindo ...

  9. WPF.UIShell UIFramework之自定义窗口的深度技术 - 模态闪动(Blink)、窗口四边拖拽支持(WmNCHitTest)、自定义最大化位置和大小(WmGetMinMaxInfo)

    无论是在工作和学习中使用WPF时,我们通常都会接触到CustomControl,今天我们就CustomWindow之后的一些边角技术进行探讨和剖析. 窗口(对话框)模态闪动(Blink) 自定义窗口的 ...

随机推荐

  1. 【温故而知新:文件操作】C#的文件读写相关

    StreamReader类以及其方法ReadLine,Read,ReadToEnd的分析 首先StreamReader类的构造参数非常丰富在这里,我觉得最常用的就是StreamReader(Strea ...

  2. 【给你几个使用Xamarin的理由】

    写在开篇前 这种代理操作,绑定影射的机制,有些极端的开发者确实难以接受.追求完美,总感觉原生的各种优点. 如果你非得较这个真,那您还是感觉补习下 Java Eclipse  ,买一台Mac 恶补Obj ...

  3. 关于导入oracle10g的数据到sqlserver2005里的方案总结

    由于项目需求,现需要将oracle的数据全部导入到sqlserver中,一下算是自己的总结小计吧. sqlserver有自己的导入数据的功能,其中就有提供两种方式从oracle导入数据. 两种方式就不 ...

  4. 04747_Java语言程序设计(一)_第8章_多线程

    例8.1应用程序用Thread子类实现多线程. import java.util.Date; public class Example8_1 { static Athread threadA; sta ...

  5. 系统中断与SA_RESTART

    今天在调试程序时,sem_timedwait居然返回了一个Interrupted system call,错误码为EINTR.系统中断这东西我一向只闻其名,不见其"人",不想今天遇 ...

  6. python高级编程之最佳实践,描述符与属性01

    # -*- coding: utf-8 -*- # python:2.x __author__ = 'Administrator' #最佳实践 """ 为了避免前面所有的 ...

  7. SqlDependency不起作用

    今天使用SqlDependency,结果不起作用,失效,不管数据库怎么修改,这边都没反应,OnChange事件总是不执行,很奇怪.我打开msdn里的例子,代码复制出来,结果没问题,能执行,那剩下来的问 ...

  8. Guice 学习(六)使用Provider注入服务( Provider Inject Service)

    1.定义接口 package com.guice.providerInject; import com.google.inject.ProvidedBy; public interface Servi ...

  9. OCR怎么能离开扫描仪呢?

    说起OCR,说来说去就是和各种各样的图片打交道. 所以图片的质量很的关键. 说起图片的质量,不得不提的就是图片的採集. 眼下最靠谱的图像採集来源就是扫描仪. 扫描仪的话就大有说法,最靠谱的扫描仪,扫描 ...

  10. map的类型映射

    以下是使用STL中map类型,对类型的转换示例,主要可以解决的问题,也就是一般的类型之间的相互转换,可以较好的解决相关的问题. 以下是C++源码,比较简短,容易理解的. #include " ...