五天拼出一款提词器软件之二软件基础代码与功能实现

根据软件需求和设计的思路,提词器主体的部分应该就是一个无框的窗体,然后叠加一个qtextedit,利用qtextedit的滚动条功能,结合qtimer实现定时滚动的功能。
有个qt编写经验的同学其实知道,如果直接用ui建立widget的模式,实现无框窗体的话,设置qtextedit背景透明是没有问题的,关键是如果要实现窗体的移动和缩放就没有那么容易的了,你不能强制客户只在某一个位置点击鼠标然后移动和拖放,客户需要傻瓜化的操作,所以就必须考虑窗体边界的自动识别以及在窗体外围拖拉鼠标进行缩放,以及鼠标在窗体任意位置点击后都可以进行窗体移动的可能。
本章尽然是为了在crtl+c和crtl+v的基础上进行拼接开发,那就祭出大杀器,程序员的参考宝库,github.com,国内是gitee,不过很多资源是搬迁自github的,那就直接github吧。打开网页,搜索qt 无框窗体,当然你也可以直接搜索提词器或者英文的关键词,也有一个开源的qpromt,不过看着感觉不是太爽,所以就从最基础的开始。
搜索关键词:FramelessWindow,无框窗体,提词器等等,然后看带qt的,日期不要太远,然后最好有点forks的。然后就找到了一个。
在这里插入图片描述

看描述,qt 无边框窗口,支持边界缩放,ok,就他了,再次感谢下分享该资源的朋友。
不过进去看下,内容太简单了,有很多功能不是需要的,而且有些监听事件重复,编译运行下,好像功能有部分并没有实现,软件最贵的是借鉴别人的思路,里面窗体和边界缩放还是不错的,直接把这个作为基础,然后把不用的代码测试删除,只保留无框窗体painter部分和边界缩放部分代码。

透明窗体刷新和重绘部分

void Widget::resizeBackground(int w, int h, int round, int margin, QColor color)
{
    //如果窗口高度与屏幕高度相同,设置全屏模式,取消白边与圆角
    if(height() == screenHeight)
        round = margin = 0;
    m_bkImg = QImage(size(), QImage::Format::Format_ARGB32);
    m_bkImg.fill(QColor(0,0,0,0));//背景透明 int r, int g, int b, int a

    QPainter painter(&m_bkImg);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.setCompositionMode(QPainter::CompositionMode_DestinationOver);

    QPainterPath painterPath;
    painter.setPen(color);
    painterPath.addRoundedRect(margin, margin, w - 2 * margin, h - 2 * margin, round, round);
    painter.fillPath(painterPath, color);

    for (int i = 0; i < margin; i++)
    {
        QPainterPath path;
        path.setFillRule(Qt::WindingFill);
        path.addRoundedRect(margin - i, margin - i, w - (margin - i) * 2, h - (margin - i) * 2, round, round);
        color.setAlpha(static_cast<int>((margin - i - 1) / (1.0 * margin) * 192));
        QPen pen(color);
        pen.setWidth(1);
        painter.setPen(pen);
        painter.drawPath(path);
    }
}

void Widget::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event)
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    painter.drawImage(0, 0, m_bkImg.scaled(this->size()));
    //qDebug()<< "paint event";
}

边界判断部分

void Widget::region(const QPoint &cursorGlobalPoint, bool &activeFlag)
{
    QRect rect = this->rect();
    QPoint tl = mapToGlobal(rect.topLeft());
    QPoint rb = mapToGlobal(rect.bottomRight());
    int x = cursorGlobalPoint.x();
    int y = cursorGlobalPoint.y();
    activeFlag = true;
    if (tl.x() + PADDING + 2 >= x && tl.x() <= x && tl.y() + PADDING + 2 >= y && tl.y() <= y) {
        m_dir = WMSZ_TOPLEFT;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if (x >= rb.x() - PADDING - 2 && x <= rb.x() && y >= rb.y() - PADDING - 2 && y <= rb.y()) {
        m_dir = WMSZ_BOTTOMRIGHT;
        this->setCursor(QCursor(Qt::SizeFDiagCursor));
    } else if (x <= tl.x() + PADDING + 2 && x >= tl.x() && y >= rb.y() - PADDING - 2 && y <= rb.y()) {
        m_dir = WMSZ_BOTTOMLEFT;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    } else if (x <= rb.x() && x >= rb.x() - PADDING - 2 && y >= tl.y() && y <= tl.y() + PADDING + 2) {
        m_dir = WMSZ_TOPRIGHT;
        this->setCursor(QCursor(Qt::SizeBDiagCursor));
    } else if (x <= tl.x() + PADDING && x >= tl.x()) {
        m_dir = WMSZ_LEFT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    } else if (x <= rb.x() && x >= rb.x() - PADDING) {
        m_dir = WMSZ_RIGHT;
        this->setCursor(QCursor(Qt::SizeHorCursor));
    } else if (y >= tl.y() && y <= tl.y() + PADDING){
        m_dir = WMSZ_TOP;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    } else if (y <= rb.y() && y >= rb.y() - PADDING) {
        m_dir = WMSZ_BOTTOM;
        this->setCursor(QCursor(Qt::SizeVerCursor));
    } else {
        m_dir = -1;
        this->setCursor(QCursor(Qt::ArrowCursor));
        activeFlag = false;
    }
}

本地事件监听与鼠标事件反馈(savexmlsetting部分是后面添加的,实现窗体移动后保存参数,下次启动后窗体实现位置记忆功能)

bool Widget::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    Q_UNUSED(result)
    if (eventType == "windows_generic_MSG" || eventType == "windows_dispatcher_MSG")
    {
        auto msg = reinterpret_cast<MSG*>(message);
        if(msg->hwnd != reinterpret_cast<HWND>(this->winId())) return false;
        if (msg->message == WM_MOUSEMOVE){
            bool activeFlag;
            region(cursor().pos(), activeFlag);
        }
        else if (msg->message == WM_SIZING){
            qDebug() << "wm sizing";
        }
        else if (msg->message == WM_MOVING){
            qDebug() << "wm moving";
        }
    }
    //qDebug() << "native event filter";
    return false;
}

void Widget::mousePressEvent(QMouseEvent *event)
{
    bool activeFlag;
    region(cursor().pos(), activeFlag);
    //qDebug() << "check left button " << activeFlag << m_dir;
    if(event->button() == Qt::LeftButton){
        if(::ReleaseCapture()){
            if (activeFlag &&  m_dir > 0) {
                ::SendMessage(HWND(this->winId()), WM_SYSCOMMAND, SC_SIZE | m_dir, 0);
            }
            ::SendMessage(HWND(this->winId()), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);

            QRect rect = this->rect();
            QPoint tl = mapToGlobal(rect.topLeft());
            posx = tl.x();
            posy = tl.y();
            savexmlsetting("posx",QString("%1").arg(posx));
            savexmlsetting("posy",QString("%1").arg(posy));
        }
        //qDebug() << "check Left Button";
    }
    else if(event->button() == Qt::RightButton){
        //qDebug() << "check Right Button";
    }
    else if(event->button() == Qt::MidButton){
        //qDebug() << "check middle Button";
    }
    //qDebug() << "mousepressevent" << event->button();
    __super::mousePressEvent(event);
}

窗体缩放后,根据缩放进行事件处理,原作者是重绘窗体,此处上面加了窗口缩放后尺寸大小的记忆功能

void Widget::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event)
    ticiW = width();
    ticiH = height();
    savexmlsetting("width",QString("%1").arg(ticiW));
    savexmlsetting("height",QString("%1").arg(ticiH));

    if(height() != screenHeight){
        m_normalSize = size();
    }
    resizeBackground(width(), height(), 0, 0, QColor(backR,backG,backB,backA));//set your like
    //qDebug() << "resizeEvent";
}

运行测试,一个可改变背景的透明窗体就ok了,大房子第一步,平面图搞定,就像一个画板,先确定布局,后面就可以在此界面上在进行后续的搭建和绘画。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wukongxuetang

如果文章对你的工作有帮助就鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值