qt 拖拽 修改大小

写次篇文章之前,qt窗口的放大缩小和拖拽我都是通过setGeometry方法实现的,但是作为windows程序,windows支持橡 皮筋式(拖拽时有一个虚框)拖拽和拉伸。通过setGeometry方式实现功能是没有这种效果,幸好qt5中提供了一个本地事件处理接口 nativeEvent,具体功能可以看帮助文档,本文只讲述用该接口实现窗口放大、缩小和拖拽,具体实现代码如下:

  1 virtual bool nativeEvent(const QByteArray &, void *, long *) Q_DECL_OVERRIDE;
  2 
  3 {
  4 
  5     Q_UNUSED(eventType);
  6 
  7     MSG* msg = reinterpret_cast(message);
  8 
  9     if (winEvent(msg, result))
 10 
 11     {
 12 
 13         return true;
 14 
 15     }
 16 
 17     else
 18 
 19     {
 20 
 21         return QWidget::nativeEvent(eventType, message, result);
 22 
 23     }
 24 
 25 }
 26 
 27 如下方法是在qt事件循环之前调用的,如果返回值为true,则该事件循环不进入qt事件循环,否则进入,result是一个输出型参数,我们可以通过赋值给result不同的值,来控制鼠标的状态
 28 
 29 HTCAPTION:鼠标可以拖拽
 30 
 31 HTLEFT / HTRIGHT:鼠标可以左右拖拽
 32 
 33 HTTOP / HTBOTTOM:鼠标可以上下拖拽
 34 
 35 HTTOPLEFT / HTBOTTOMRIGHT:鼠标可以左上或者右下拖拽
 36 
 37 HTTOPRIGHT / HTBOTTOMLEFT:鼠标可以右上或者左下拖拽
 38 
 39 bool CCailianMainWindow::winEvent(MSG *message, long *result)
 40 
 41 {
 42 
 43     static int width = 4;//可检测到鼠标状态的宽度
 44 
 45     bool res = false;
 46 
 47     if (isMaximized())
 48 
 49     {
 50 
 51         return res;
 52 
 53     }
 54 
 55     switch (message->message)
 56 
 57     {
 58 
 59     case WM_NCHITTEST:
 60 
 61         int xPos = GET_X_LPARAM(message->lParam) - this->frameGeometry().x();
 62 
 63         int yPos = GET_Y_LPARAM(message->lParam) - this->frameGeometry().y();
 64 
 65         if (QWidget * childW = this->childAt(xPos, yPos))
 66 
 67         {
 68 
 69             if (childW == m_WindowTitle)//我自己的窗口头,支持鼠标拖拽
 70 
 71             {
 72 
 73                 *result = HTCAPTION;
 74 
 75                 res = true;
 76 
 77             }
 78 
 79         }
 80 
 81         else
 82 
 83         {
 84 
 85             return res;
 86 
 87         }
 88 
 89         if (xPos >= 0 && xPos < width)
 90 
 91         {
 92 
 93             *result = HTLEFT;
 94 
 95             res = true;
 96 
 97         }
 98 
 99         if (xPos > (this->width() - width) && xPos < this->width())
100 
101         {
102 
103             *result = HTRIGHT;
104 
105             res = true;
106 
107         }
108 
109         if (yPos >= 0 && yPos < width)
110 
111         {
112 
113             *result = HTTOP;
114 
115             res = true;
116 
117         }
118 
119         if (yPos > (this->height() - width) && yPos < this->height())
120 
121         {
122 
123             *result = HTBOTTOM;
124 
125             res = true;
126 
127         }
128 
129         if (xPos >= 0 && xPos < width && yPos >= 0 && yPos < width)
130 
131         {
132 
133             *result = HTTOPLEFT;
134 
135             res = true;
136 
137         }
138 
139         if (xPos > (this->width() - width) && xPos < this->width() && yPos >= 0 && yPos < width)
140 
141         {
142 
143             *result = HTTOPRIGHT;
144 
145             res = true;
146 
147         }
148 
149         if (xPos >= 0 && xPos < width && yPos >(this->height() - width) && yPos < this->height())
150 
151         {
152 
153             *result = HTBOTTOMLEFT;
154 
155             res = true;
156 
157         }
158 
159         if (xPos > (this->width() - width) && xPos < this->width() && yPos >(this->height() - width) && yPos < this->height())
160 
161         {
162 
163             *result = HTBOTTOMRIGHT;
164 
165             res = true;
166 
167         }
168 
169     }
170 
171     return res;
172 
173 }
View Code
图1 拖拽
图2 修改大小 

如上图所示,红色箭头指的就是拖拽和改变大小时出现的白色框

这样处理后的标题栏(m_WindowTitle)不能接受到mouseDoubleClickEvent事件,因此还需要自己手动修改窗口大小,代码如下,添加到上述swtich语句中

 1 case WM_NCLBUTTONDBLCLK:
 2 
 3 {
 4 
 5     HWND hWnd = (HWND)this->winId();
 6 
 7     if (::IsZoomed(hWnd))
 8 
 9     {
10 
11         ShowWindow(hWnd, SW_RESTORE);
12 
13     }
14 
15     else
16 
17     {
18 
19         ShowWindow(hWnd, SW_MAXIMIZE);
20 
21     }
22 
23     res = false;
24 
25 }
26 
27 break;
View Code

注意:要支持windows的这种特性,需要通过代码设置

showFullWindow:true代表拖动和改变大小时窗口实时变化;false代表橡皮筋式放大,如上图所示

SystemParametersInfo(SPI_SETDRAGFULLWINDOWS, showFullWindow ? TRUE : FALSE, NULL, 0);

 

================================================

时隔10几天,当我测试新功能时发现一个问题,特此记录:

在xp系统上qt程序没有任务栏菜单,但是win7和win10正常,给qt程序手动添加​Qt::WindowSystemMenuHint属性后,3系统都有菜单,但是nativeEvent方法不能放大缩小了,解决办法暂时没找到

====================================

今儿突然想到QMainWindow,这个右下角有一个可以支持放大做小的功能,最后看了源码,发现由一个QSizeGrip类,这个类可以实现所在顶层 QWindow的放大和缩小,特此记录​,此时结果如下图3。这个类支持橡皮筋放大缩小,和前文所述nativeEvent实现效果相同

图3 QSizeGrip实例
<think>好的,我现在要解决用户的问题:在Qt中如何调整画布大小或调整绘图区域的尺寸。首先,我需要回忆一下Qt框架中与绘图相关的组件和类。Qt中常用的绘图是在QWidget的paintEvent方法中进行的,或者使用QGraphicsView和QGraphicsScene来管理绘图区域。调整画布的大小可能涉及调整QWidget的尺寸,或者调整QGraphicsScene的尺寸。 首先,用户提到的是“画布”或“绘图区域”,这可能指的是一个自定义的QWidget,用户在其上进行绘制。在这种情况下,调整画布大小可能直接通过设置QWidget的大小来实现。例如,调用resize()方法或者设置固定尺寸。但用户可能需要的是在绘图时动态调整绘图的区域,而不仅仅是改变窗口大小。这时候可能需要考虑如何管理绘图的坐标系或视口。 另外,Qt中的QGraphicsView和QGraphicsScene提供了一个更复杂的绘图框架,允许管理大量的图形项,并且可以方便地调整视图和场景的大小。如果用户使用的是QGraphicsView,调整场景的大小可能需要设置场景的sceneRect,或者调整视图的视口尺寸。 接下来,我需要考虑具体的实现步骤。例如,如果用户有一个继承自QWidget的自定义绘图类,他们可能需要在该类中重写resizeEvent,以便在窗口大小变化时调整内部的绘图区域参数。或者,在绘图时根据当前的widget尺寸来动态计算绘制的内容的位置和大小。 另外,可能还需要处理高DPI屏幕的缩放问题,确保绘图在不同分辨率下显示正确。Qt提供了相关的方法,比如设置属性Qt::AA_EnableHighDpiScaling,或者在绘制时使用devicePixelRatio来调整坐标和尺寸。 然后,我需要考虑如何将这些步骤转化为具体的代码示例。比如,展示一个自定义QWidget的实现,其中在resizeEvent中更新存储画布尺寸的变量,并在paintEvent中使用这些变量来绘制内容。或者,在QGraphicsView中设置场景的尺寸,并确保视图正确显示整个场景。 可能还需要提到布局管理,如果画布部件被包含在布局中,调整其大小时可能需要调整布局的设置,或者设置尺寸策略。例如,使用setSizePolicy来允许部件扩展或收缩。 此外,用户可能想知道如何通过用户交互来调整画布大小,例如拖动窗口边缘或者通过按钮来改变尺寸。这可能需要结合信号和槽机制,在用户操作时触发尺寸调整的函数。 最后,我需要验证这些方法是否正确,是否有遗漏的步骤或常见的错误。例如,忘记调用update()导致界面不刷新,或者在调整尺寸时没有正确处理坐标变换,导致绘制内容错位。 总结下来,调整画布大小的方法可能包括: 1. 直接调整QWidget的尺寸,使用resize()或setFixedSize()。 2. 在自定义QWidget中管理绘图区域的变量,根据部件尺寸动态调整绘制内容。 3. 在QGraphicsView/QGraphicsScene中设置场景或视图的尺寸。 4. 处理高DPI缩放,确保绘图在不同分辨率下正确显示。 5. 结合布局管理和尺寸策略,使画布能够自适应窗口变化。</think>在Qt中调整画布或绘图区域的尺寸,可以通过以下方法实现: --- ### 方法一:调整QWidget尺寸(基础绘图) 1. **自定义QWidget子类**:创建继承自`QWidget`的绘图区域,重写`paintEvent`和`resizeEvent`。 ```cpp class Canvas : public QWidget { public: void resizeEvent(QResizeEvent* event) override { // 保存新尺寸 m_canvasSize = event->size(); update(); // 触发重绘 } void paintEvent(QPaintEvent*) override { QPainter painter(this); painter.fillRect(rect(), Qt::white); // 根据新尺寸绘制背景 // 其他绘制逻辑... } private: QSize m_canvasSize; }; ``` 2. **动态调整尺寸**:通过外部按钮或代码直接调整Widget尺寸。 ```cpp canvas->resize(newWidth, newHeight); // 直接调整大小 // 或设置固定尺寸 canvas->setFixedSize(800, 600); ``` --- ### 方法二:使用QGraphicsView/QGraphicsScene(复杂绘图) 1. **设置场景尺寸**: ```cpp QGraphicsScene* scene = new QGraphicsScene(); scene->setSceneRect(0, 0, 1000, 800); // 设置场景的初始大小 QGraphicsView* view = new QGraphicsView(scene); ``` 2. **动态调整视图与场景**: ```cpp // 调整视图显示的区域(视口) view->fitInView(scene->sceneRect(), Qt::KeepAspectRatio); // 调整场景大小 scene->setSceneRect(newX, newY, newWidth, newHeight); ``` --- ### 方法三:处理高DPI缩放 在`main.cpp`中启用高DPI支持: ```cpp QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication app(argc, argv); ``` 在绘制时根据设备像素比调整坐标: ```cpp void Canvas::paintEvent(QPaintEvent*) { QPainter painter(this); qreal dpr = devicePixelRatio(); painter.scale(dpr, dpr); // 缩放坐标系 } ``` --- ### 布局管理 将画布部件放入布局中,使其随窗口自动调整: ```cpp QHBoxLayout* layout = new QHBoxLayout; layout->addWidget(canvasWidget); mainWindow->setLayout(layout); // 设置尺寸策略 canvasWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值