Qt:调整无边框小部件的大小

2023-11-24

我的问题基本上与this one,但应用于 Qt C++ 框架。

我通过继承带有标志 Qt::QPopup | 的 QWidget 来实现弹出窗口Qt::QWindow。我希望这个窗口是可移动和可调整大小的,我目前通过使用以下代码中的鼠标事件来实现这一点:

void TextPopup::mousePressEvent(QMouseEvent* event)
{
    offset = event->pos();
    QWidget::mousePressEvent(event);
}

void TextPopup::mouseMoveEvent(QMouseEvent* event)
{
    if(event->buttons() & Qt::LeftButton)
        if(resizeMode) {
            QPoint p = mapToGlobal(event->pos()) - geometry().topLeft();
            resize(p.x(), p.y());
        } else
            move(mapToParent(event->pos() - offset));
    else {
        QPoint diff = geometry().bottomRight() - mapToGlobal(event->pos());
        if(diff.x() <= 6 && diff.y() <= 6) {
            if(!resizeMode) {
                setCursor(Qt::SizeFDiagCursor);
                resizeMode = true;
            }
        } else {
            if(resizeMode) {
                setCursor(Qt::SizeAllCursor);
                resizeMode = false;
            }
        }
    }
}

void TextPopup::mouseReleaseEvent(QMouseEvent* event)
{
    offset = QPoint();
    QWidget::mouseReleaseEvent(event);
}

我对此有一些问题。一方面,我猜有更好的方法来做到这一点。更重要的是,我想要右下角的调整大小符号,如图所示](取自上面提到的帖子)。对于实现这一目标有什么建议吗?

enter image description here


如果你不想QSizeGrip你可以看看这个解决方案:

frameless.h:

#pragma once
#include <QtWidgets/QWidget>
#include <QtWidgets/QRubberBand>
#include <QtCore/QObject>
#include <QtCore/QEvent>
#include <QtCore/QRect>
#include <QtCore/QPoint>
#include <QtCore/Qt>
#include <QtGui/QHoverEvent>
#include <QtGui/QMouseEvent>

class FrameLess : public QObject {
    Q_OBJECT

public:
    enum Edge {
        None = 0x0,
        Left = 0x1,
        Top = 0x2,
        Right = 0x4,
        Bottom = 0x8,
        TopLeft = 0x10,
        TopRight = 0x20,
        BottomLeft = 0x40,
        BottomRight = 0x80,
    };
    Q_ENUM(Edge);
    Q_DECLARE_FLAGS(Edges, Edge);

    FrameLess(QWidget *target);

    void setBorderWidth(int w) {
        _borderWidth = w;
    }
    int borderWidth() const {
        return _borderWidth;
    }

protected:
    bool eventFilter(QObject *o, QEvent *e) override;
    void mouseHover(QHoverEvent*);
    void mouseLeave(QEvent*);
    void mousePress(QMouseEvent*);
    void mouseRealese(QMouseEvent*);
    void mouseMove(QMouseEvent*);
    void updateCursorShape(const QPoint &);
    void calculateCursorPosition(const QPoint &, const QRect &, Edges &);

private:
    QWidget *_target = nullptr;
    QRubberBand *_rubberband = nullptr;
    bool _cursorchanged;
    bool _leftButtonPressed;
    Edges _mousePress = Edge::None;
    Edges _mouseMove = Edge::None;
    int _borderWidth;

    QPoint _dragPos;
    bool _dragStart = false;
};

Q_DECLARE_OPERATORS_FOR_FLAGS(FrameLess::Edges);

frameless.cpp:

#include "frameless.h"

FrameLess::FrameLess(QWidget *target) :
    _target(target),
    _cursorchanged(false),
    _leftButtonPressed(false),
    _borderWidth(5),
    _dragPos(QPoint())
{
    _target->setMouseTracking(true);
    _target->setWindowFlags(Qt::FramelessWindowHint);
    _target->setAttribute(Qt::WA_Hover);
    _target->installEventFilter(this);
    _rubberband = new QRubberBand(QRubberBand::Rectangle);
}

bool FrameLess::eventFilter(QObject *o, QEvent*e) {
    if (e->type() == QEvent::MouseMove ||
        e->type() == QEvent::HoverMove ||
        e->type() == QEvent::Leave ||
        e->type() == QEvent::MouseButtonPress ||
        e->type() == QEvent::MouseButtonRelease) {

        switch (e->type()) {
        case QEvent::MouseMove:
            mouseMove(static_cast<QMouseEvent*>(e));
            return true;
            break;
        case QEvent::HoverMove:
            mouseHover(static_cast<QHoverEvent*>(e));
            return true;
            break;
        case QEvent::Leave:
            mouseLeave(e);
            return true;
            break;
        case QEvent::MouseButtonPress:
            mousePress(static_cast<QMouseEvent*>(e));
            return true;
            break;
        case QEvent::MouseButtonRelease:
            mouseRealese(static_cast<QMouseEvent*>(e));
            return true;
            break;
        }
    }
    else {
        return _target->eventFilter(o, e);
    }
}

void FrameLess::mouseHover(QHoverEvent *e) {
    updateCursorShape(_target->mapToGlobal(e->pos()));
}

void FrameLess::mouseLeave(QEvent *e) {
    if (!_leftButtonPressed) {
        _target->unsetCursor();
    }
}

void FrameLess::mousePress(QMouseEvent *e) {
    if (e->button() & Qt::LeftButton) {
        _leftButtonPressed = true;
        calculateCursorPosition(e->globalPos(), _target->frameGeometry(), _mousePress);
        if (!_mousePress.testFlag(Edge::None)) {
            _rubberband->setGeometry(_target->frameGeometry());
        }
        if (_target->rect().marginsRemoved(QMargins(borderWidth(), borderWidth(), borderWidth(), borderWidth())).contains(e->pos())) {
            _dragStart = true;
            _dragPos = e->pos();
        }
    }
}

void FrameLess::mouseRealese(QMouseEvent *e) {
    if (e->button() & Qt::LeftButton) {
        _leftButtonPressed = false;
        _dragStart = false;
    }
}

void FrameLess::mouseMove(QMouseEvent *e) {
    if (_leftButtonPressed) {
        if (_dragStart) {
            _target->move(_target->frameGeometry().topLeft() + (e->pos() - _dragPos));
        }

        if (!_mousePress.testFlag(Edge::None)) {
            int left = _rubberband->frameGeometry().left();
            int top = _rubberband->frameGeometry().top();
            int right = _rubberband->frameGeometry().right();
            int bottom = _rubberband->frameGeometry().bottom();
            switch (_mousePress) {
            case Edge::Top:
                top = e->globalPos().y();
                break;
            case Edge::Bottom:
                bottom = e->globalPos().y();
                break;
            case Edge::Left:
                left = e->globalPos().x();
                break;
            case Edge::Right:
                right = e->globalPos().x();
                break;
            case Edge::TopLeft:
                top = e->globalPos().y();
                left = e->globalPos().x();
                break;
            case Edge::TopRight:
                right = e->globalPos().x();
                top = e->globalPos().y();
                break;
            case Edge::BottomLeft:
                bottom = e->globalPos().y();
                left = e->globalPos().x();
                break;
            case Edge::BottomRight:
                bottom = e->globalPos().y();
                right = e->globalPos().x();
                break;
            }
            QRect newRect(QPoint(left, top), QPoint(right, bottom));
            if (newRect.width() < _target->minimumWidth()) {
                left = _target->frameGeometry().x();
            }
            else if (newRect.height() < _target->minimumHeight()) {
                top = _target->frameGeometry().y();
            }
            _target->setGeometry(QRect(QPoint(left, top), QPoint(right, bottom)));
            _rubberband->setGeometry(QRect(QPoint(left, top), QPoint(right, bottom)));
        }
    }
    else {
        updateCursorShape(e->globalPos());
    }
}

void FrameLess::updateCursorShape(const QPoint &pos) {
    if (_target->isFullScreen() || _target->isMaximized()) {
        if (_cursorchanged) {
            _target->unsetCursor();
        }
        return;
    }
    if (!_leftButtonPressed) {
        calculateCursorPosition(pos, _target->frameGeometry(), _mouseMove);
        _cursorchanged = true;
        if (_mouseMove.testFlag(Edge::Top) || _mouseMove.testFlag(Edge::Bottom)) {
            _target->setCursor(Qt::SizeVerCursor);
        }
        else if (_mouseMove.testFlag(Edge::Left) || _mouseMove.testFlag(Edge::Right)) {
            _target->setCursor(Qt::SizeHorCursor);
        }
        else if (_mouseMove.testFlag(Edge::TopLeft) || _mouseMove.testFlag(Edge::BottomRight)) {
            _target->setCursor(Qt::SizeFDiagCursor);
        }
        else if (_mouseMove.testFlag(Edge::TopRight) || _mouseMove.testFlag(Edge::BottomLeft)) {
            _target->setCursor(Qt::SizeBDiagCursor);
        }
        else if (_cursorchanged) {
            _target->unsetCursor();
            _cursorchanged = false;
        }
    }
}

void FrameLess::calculateCursorPosition(const QPoint &pos, const QRect &framerect, Edges &_edge) {
    bool onLeft = pos.x() >= framerect.x() - _borderWidth && pos.x() <= framerect.x() + _borderWidth &&
        pos.y() <= framerect.y() + framerect.height() - _borderWidth && pos.y() >= framerect.y() + _borderWidth;

    bool onRight = pos.x() >= framerect.x() + framerect.width() - _borderWidth && pos.x() <= framerect.x() + framerect.width() &&
        pos.y() >= framerect.y() + _borderWidth && pos.y() <= framerect.y() + framerect.height() - _borderWidth;

    bool onBottom = pos.x() >= framerect.x() + _borderWidth && pos.x() <= framerect.x() + framerect.width() - _borderWidth  &&
        pos.y() >= framerect.y() + framerect.height() - _borderWidth && pos.y() <= framerect.y() + framerect.height();

    bool onTop = pos.x() >= framerect.x() + _borderWidth && pos.x() <= framerect.x() + framerect.width() - _borderWidth &&
        pos.y() >= framerect.y() && pos.y() <= framerect.y() + _borderWidth;

    bool  onBottomLeft = pos.x() <= framerect.x() + _borderWidth && pos.x() >= framerect.x() &&
        pos.y() <= framerect.y() + framerect.height() && pos.y() >= framerect.y() + framerect.height() - _borderWidth;

    bool onBottomRight = pos.x() >= framerect.x() + framerect.width() - _borderWidth && pos.x() <= framerect.x() + framerect.width() &&
        pos.y() >= framerect.y() + framerect.height() - _borderWidth && pos.y() <= framerect.y() + framerect.height();

    bool onTopRight = pos.x() >= framerect.x() + framerect.width() - _borderWidth && pos.x() <= framerect.x() + framerect.width() &&
        pos.y() >= framerect.y() && pos.y() <= framerect.y() + _borderWidth;

    bool onTopLeft = pos.x() >= framerect.x() && pos.x() <= framerect.x() + _borderWidth &&
        pos.y() >= framerect.y() && pos.y() <= framerect.y() + _borderWidth;

    if (onLeft) {
        _edge = Left;
    }
    else if (onRight) {
        _edge = Right;
    }
    else if (onBottom) {
        _edge = Bottom;
    }
    else if (onTop) {
        _edge = Top;
    }
    else if (onBottomLeft) {
        _edge = BottomLeft;
    }
    else if (onBottomRight) {
        _edge = BottomRight;
    }
    else if (onTopRight) {
        _edge = TopRight;
    }
    else if (onTopLeft) {
        _edge = TopLeft;
    }
    else {
        _edge = None;
    }
}

只需创建一个实例并将您的QWidget:

#include "frameless.h"
#include <QtWidgets/qapplication.h>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    QWidget *widget = new QWidget;
    FrameLess f(widget);
    widget->show();
    return a.exec();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt:调整无边框小部件的大小 的相关文章

  • 我们如何将数据从一个打开的表单传递到另一个打开的表单?

    winform中如何将数据从一个窗体传递到另一个打开的窗体 在 Windows 应用程序中 一个窗体打开另一个窗体 当我在父表单中输入一些数据时 这些数据将立即反映在另一个子表单中 这将如何发生 取决于你想要多花哨 最简单的方法就是直接调用
  • 将列表(对象)转换为列表(字符串)

    有没有办法转换List of Object to a List of String 在 c 或 vb net 中而不迭代所有项目 幕后迭代很好 我只想要简洁的代码 Update 最好的方法可能就是进行新的选择 myList Select f
  • 具有多重继承的类的 sizeof

    首先 我知道 sizeof 取决于机器和编译器的实现 我使用的是 Windows 8 1 x64 gcc 5 3 0 没有标志传递给编译器 我从大学讲座中得到了以下代码 include
  • 返回指向 std::vector 中的对象的 a

    我有一个关于返回对向量元素的引用的非常基本的问题 有一个向量vec存储类的实例Foo 我想访问这个向量中的一个元素 不想使用向量索引 我应该如何编码该方法getFoo here include
  • C 中“for”循环中的两个变量

    我正在编写一些代码 需要在其中使用两个变量for环形 下面的代码看起来没问题吗 它确实给了我预期的结果 for loop 1 offset loop 2 offset 2 loop 1 gt offset 190 loop 2 lt 190
  • Qt中如何获取鼠标在屏幕上的位置?

    我想获取屏幕上的鼠标坐标 我怎样才能在 Qt 中做到这一点 在 Windows 上 使用 C 我正在做类似答案中建议的事情对于这个问题 https stackoverflow com q 11737665 1420197 正如文档所述 QC
  • 替换 JSON 中的转义字符

    我想用空格替换 JSON 字符串中的 字符 我怎样才能做到这一点 我发现从 JSON 字符串中删除所有转义字符的最简单 最好的方法是将字符串传递到正则表达式 Unescape 方法 此方法返回一个没有转义字符的新字符串 甚至删除了 n t
  • 获取给定EntityType的导航属性

    我在用VS2010 EF4 0 需要如下功能 private string GetNaviProps Type entityType eg typeof Employee NorthwindEntities en new Northwind
  • 从窗口内容截取屏幕截图(无边框)

    我正在寻找有关如何使用 C 将表单内容保存在位图中的解决方案 我已经尝试过使用 DrawToBitmap 但它捕获了所有带边框的窗口 这就是这段代码的结果 public static Bitmap TakeDialogScreenshot
  • 在 ncurses 中使用退格键

    我设置了一个简单的 ncurses 程序 它使用 getch 一次读取一个字符并将它们复制到缓冲区中 我遇到的问题是检测到按下退格键 这是相关代码 while buffer i c getch EOF i if c n break else
  • 在不使用 Thread.Sleep c# 的情况下延迟发送电子邮件

    我有一个 for 循环 它循环并每个循环发送一封电子邮件 现在我正在使用 thread sleep 但我希望用户仍然能够与程序交互 只需取消该循环即可 是否可以在不使用 thread sleep 的情况下做到这一点 您是否在 UI 线程上运
  • 如何用C++解析复杂的字符串?

    我试图弄清楚如何使用 解析这个字符串sstream 和C 其格式为 string int int 我需要能够将包含 IP 地址的字符串的第一部分分配给 std string 以下是该字符串的示例 std string 127 0 0 1 1
  • 简单的文档管理系统和API [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • std::string 在 Visual Studio 上的具体行为?

    我有一个项目需要读取 写入大文件 我决定使用 ifstream read 将这些文件一次性放入内存中 放入 std string 中 这似乎是在 C 中执行此操作的最快方法 http insanecoding blogspot com 20
  • 无法将方法组“Read”转换为非委托类型“bool”

    我正在尝试使用SqlDataReader检查条目是否存在 如果存在则返回ID 否则返回false 当我尝试编译时 出现错误 无法将方法组 Read 转换为非委托类型 bool 我一直在遵循在 VB 中找到的示例 但似乎翻译可能不正确 pri
  • C 的“char”使用什么字符集? [复制]

    这个问题在这里已经有答案了 简单的问题 我最近开始用 C 编程 有一个简单的问题 C 编程语言在其 char 类型中使用什么字符集 例如 ASCII 还是取决于软件 操作系统 char 本质上是 1 个字节 主要在所有操作系统上 所以默认情
  • win32 API 和 .NET 框架之间的选择

    我必须开发一个适用于 Windows 的应用程序 该应用程序将能够通过网络摄像头识别手势来控制鼠标 我将使用 vc 2008 进行开发 但我很困惑是使用 NET 框架还是核心 win32 API 性能对于我的应用程序非常重要 根据 Ivor
  • 使用 roslyn 扩展 C# 语法

    我试图在没有 else 情况的情况下实现 return if return value if 因为我只想在条件有效时返回或返回一个值 我知道 有if condition return or if condition return value
  • FakeItEasy 代理方法调用实际实现

    我正在尝试将对假对象的调用代理到实际的实现 这样做的原因是我希望能够使用 Machine Specifications 的 WasToldTo 和 WhenToldTo 它们仅适用于接口类型的伪造 因此 我正在执行以下操作来代理对我的真实对
  • 如何将 char 转换为 unsigned int?

    我有一个字符数组 它实际上用作字节数组 而不是用于存储文本 在数组中 有两个特定字节表示我需要存储到无符号 int 值中的数值 下面的代码解释了设置 char bytes bytes 2 bytes 0 0x0C For the sake

随机推荐