QT保持窗口宽高比

您所在的位置:网站首页 widget设置固定大小 QT保持窗口宽高比

QT保持窗口宽高比

2024-07-12 07:38| 来源: 网络整理| 查看: 265

需求

由于窗口功能特殊,需要保持窗口的宽高比不变。即在调整宽度的时候同时自动调整宽度,同理在调整宽度的时候同时自动调整高度。

资料收集 resizeEvent() 在QWidget中当窗口大小改变之后会触发resizeEvent事件。setHeightForWidth() 非顶级窗口可用,设置此属性后,在窗口的宽度发生更改之后会自动调用heightForWidth函数来获取新的高度。WM_SIZING MFC中的一个消息,指示窗口的大小即将改变。 分析整理

首先,resizeEvent()事件是在窗口大小发生改变之后才触发的,而且在代码中使用resize()函数来设置窗口的大小同样会触发此事件。 因此如果resizeEvent()触发的慢的话应该可以看到窗口跳动,而稍微处理不好的话很有可能导致循环。 其次,setHeightForWidth()据网上的资料说此方法只能用于非顶级窗口。所以没法用。 那么就只剩下WM_SIZING这条思路了。 因为QT和MFC是可以同时使用的,也就是说QT和MFC兼容性还可以。以前使用MFC的方式给QT窗口发送过消息,那么QT中是否有和WM_SIZING相对应的方法或事件?

开始行动 查文档 首先在已经实现的部分事件相应函数中没有找到。而在QEvent::Type的说明中也没有找到相应的事件类型。试一试 在文档中没有明确找到的话。就只能试了。重载bool event(QEvent *event);函数然后调试看看在窗口尺寸改变之前我们会收到哪些消息。

首先,重载event()函数

bool XPianoKeyboard::event(QEvent * event) { qDebug() type()) { case QEvent::MouseButtonPress: { //鼠标点击,进入调整大小模式 QMouseEvent* me = static_cast(event); if (m_RT != RT_Unknow) { //记录一些信息 m_oldSize = pw->size(); m_oldPos = pw->frameGeometry().topLeft(); pw->grabMouse(); //pw->setFixedSize(m_oldSize); QMouseEvent* me = static_cast(event); m_oldPoint = me->globalPos(); //捕获鼠标 m_bSizing = true; } } case QEvent::HoverMove: //QMainWindow 类型的窗口收到的是这个消息,而不是MouseMove //但是这个消息只有在鼠标未点击的时候能收到 if (!m_bSizing) { QHoverEvent* me = static_cast(event); //是否是要横向调整大小 bool bhor = me->pos().x() > m_oldSize.width() - 5 || me->pos().x() < 5; //是否是要纵向调整大小 bool bver = me->pos().y() > m_oldSize.height() - 5; if (bhor && bver) if (me->pos().x() < 5) { pw->setCursor(Qt::SizeBDiagCursor); m_RT = RT_BottomLeft; } else { pw->setCursor(Qt::SizeFDiagCursor); m_RT = RT_BottomRight; } else if (bhor) { pw->setCursor(Qt::SizeHorCursor); if (me->pos().x() < 5) m_RT = RT_Left; else m_RT = RT_Right; } else if (bver) { pw->setCursor(Qt::SizeVerCursor); m_RT = RT_Bottom; } else { //鼠标在窗口内移动,重置状态,还原鼠标样式 m_RT = RT_Unknow; pw->unsetCursor(); } } break; case QEvent::MouseMove: { //捕获鼠标之后收到的消息,在这里调整窗口大小 if (m_bSizing) { //QRect r = frameGeometry(); QMouseEvent* me = static_cast(event); QPoint p = me->globalPos(); ChangeSize(pw,p); } else { QMouseEvent* me = static_cast(event); //是否是要横向调整大小 bool bhor = me->pos().x() > m_oldSize.width() - 5 || me->pos().x() < 5; //是否是要纵向调整大小 bool bver = me->pos().y() > m_oldSize.height() - 5; if (bhor && bver) if (me->pos().x() < 5) { pw->setCursor(Qt::SizeBDiagCursor); m_RT = RT_BottomLeft; } else { pw->setCursor(Qt::SizeFDiagCursor); m_RT = RT_BottomRight; } else if (bhor) { pw->setCursor(Qt::SizeHorCursor); if (me->pos().x() < 5) m_RT = RT_Left; else m_RT = RT_Right; } else if (bver) { pw->setCursor(Qt::SizeVerCursor); m_RT = RT_Bottom; } else { //鼠标在窗口内移动,重置状态,还原鼠标样式 m_RT = RT_Unknow; pw->unsetCursor(); } } } break; case QEvent::MouseButtonRelease: { //退出鼠标调整模式 m_oldSize = pw->size(); pw->releaseMouse(); m_bSizing = false; //pw->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); } break; case QEvent::Show: //如果窗口在实例创建之后才显示出来, //在此处获取窗口尺寸和最小尺寸 m_oldSize = pw->frameGeometry().size(); m_minSize = pw->minimumSizeHint(); //设置固定大小,这样窗口不再可以调整大小 pw->setFixedSize(m_oldSize); m_AspectRatio = 1.0 * m_oldSize.width() / m_oldSize.height(); break; default: qDebug() type(); break; } return false; } /*********尺寸计算函数*********/ void XAspectRatioCtl::ChangeSize(QWidget * pw, QPoint np) { QPoint cp = np - m_oldPoint; QSize newSize; QPoint newPos = {0,0}; //当从左边调整窗口大小时还需要移动窗口 switch (m_RT) { case XAspectRatioCtl::RT_Left: //从左边调整大小,直接设置宽度值,然后根据宽度值计算高度值 newSize.setWidth(m_oldSize.width() - cp.x()); newSize.setHeight(newSize.width() / m_AspectRatio); newPos.setY(m_oldPos.y()); newPos.setX(np.x()); break; case XAspectRatioCtl::RT_Right: //从右边调整大小,直接设置宽度值,然后根据宽度值计算高度值 newSize.setWidth(m_oldSize.width() + cp.x()); newSize.setHeight(newSize.width() / m_AspectRatio); break; case XAspectRatioCtl::RT_Bottom: //从下方调整大小,直接设置高度值,然后根据高度值计算宽度值 newSize.setHeight(m_oldSize.height() + cp.y()); newSize.setWidth(newSize.height() * m_AspectRatio); break; case XAspectRatioCtl::RT_BottomLeft: { //先计算宽度和高度值, int nh = m_oldSize.height() + cp.y(); int nw = m_oldSize.width() - cp.x(); //取较小尺寸值,然后计算确切尺寸 if (nw > nh * m_AspectRatio) { newSize.setHeight(nh); newSize.setWidth(nh*m_AspectRatio); } else { newSize.setWidth(nw); newSize.setHeight(nw / m_AspectRatio); } newPos.setY(m_oldPos.y()); //根据调整后的尺寸和调整前的尺寸来计算x轴移动位置 newPos.setX(m_oldPos.x() - (newSize.width() - m_oldSize.width())); } break; case XAspectRatioCtl::RT_BottomRight: { int nh = m_oldSize.height() + cp.y(); int nw = m_oldSize.width() + cp.x(); if (nw > nh * m_AspectRatio) { newSize.setHeight(nh); newSize.setWidth(nh*m_AspectRatio); } else { newSize.setWidth(nw); newSize.setHeight(nw / m_AspectRatio); } } break; default: break; } //如果调整后的大小小于最小允许的大小,则不进行调整 if (newSize.height() < m_minSize.height() || newSize.width() < m_minSize.width()) { return; } pw->setFixedSize(newSize); if (newPos != QPoint(0,0)) { pw->move(newPos); } } 成品

最后根据以上思路。写了一个控制类XAspectRatioCtl在初始化该类实例的时候传入QWidget或QMainWindow指针,则被监控的窗口在初次显示后即可保持其宽高比。 具体代码见附件:https://download.csdn.net/download/u014410266/12470183。

环境

vs2017 + QT 5.12.5



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3