【问题标题】:Any way to temporarily stop layout recalculation?有什么方法可以暂时停止重新计算布局?
【发布时间】:2014-10-20 18:09:31
【问题描述】:

我正在实现一个拖放事件过滤器来重新排列布局中的小部件,然后将其中的几个弹出到队列中,在拖动的小部件所在的位置添加一个橡皮筋,然后添加其余的小部件回到布局(因为似乎没有办法使用 QLayout 界面“插入”),如下所示:

// HANDLE DRAG ENTER EVENTS
if (p_event->type() == QEvent::DragEnter)
{
    QDragEnterEvent* dragEnterEvent = static_cast<QDragEnterEvent*>(p_event);
    if (dragEnterEvent->mimeData()->hasFormat("text/plain"))
    {
        QString objectName = dragEnterEvent->mimeData()->text();

        // findChild doesn't work on layouts because they don't ever
        // inject themselves into the parent/child hierarchy, so we
        // use the itemAt approach instead.
        for (int i = 0; i < layout->count(); ++i)
        {
            dragItem = layout->itemAt(i)->widget();
            if (dragItem->objectName() == objectName)
            {
                dragEnterEvent->acceptProposedAction();

                // 'Rearrange' the widgets. This basically entails removing
                // everything after the drag item, adding a placeh older, and 
                // then adding them back
                QQueue<QWidget*> fifo; 

                // take everything after the drag item out
                // important to have count as a local var, because otherwise it will 
                // decrement with every loop iteration.
                int count = layout->count();                        
                for (int j = i + 1; j < count; j++)
                {
                    fifo.enqueue(layout->takeAt(i+1)->widget());        // the indices shift left on their own, so we only ever want to take i+1.                           
                }

                // add a 'rubber band' placeholder
                m_band = new QRubberBand(QRubberBand::Rectangle);
                m_band->setObjectName("placeholderBand");
                m_band->setVisible(true);
                m_band->setFixedSize(dragItem->size());
                layout->addWidget(m_band);              

                // put the widgets in the fifo back in
                count = fifo.count();
                for(int j = 0; j < count; j++)
                {
                    layout->addWidget(fifo.dequeue());
                }

                break;
            }
        }
    }               
}

这种方法的问题是添加/删除小部件会导致非常明显且令人讨厌的闪烁。有没有

  1. 我可以通过某种方式阻止布局自行重新计算,直到完成所有添加/删除操作,或者
  2. 将小部件插入布局的更好方法(仅使用QLayout 界面)不会导致闪烁?

【问题讨论】:

  • 是的,你是对的,我看到了更多的源代码,在 addWidget 内部只有 addChildWidget(w); addItem(QLayoutPrivate::createWidgetItem(this, w)); 并且没有一个方法不会调用 update 或其他方法

标签: c++ qt qlayout


【解决方案1】:

不确定它是否有帮助,因为我在不同的上下文中使用(语义语法突出显示,在我的项目 loqt 中)。

#ifndef BLOCKSIG_H
#define BLOCKSIG_H

#include <QObject>
#include <QPointer>

/** temporary stop signals communication
 *  use with care: notably QTextEdit formatting can be lost
 *  on multiple changes notification
 */
struct blockSig {

    blockSig(QObject* target) : target(target) { current = target->blockSignals(true); }
    ~blockSig() { off(); }

    void off() { if (target) { target->blockSignals(current); target = 0; } }

private:

    QPointer<QObject> target;
    bool current;
};

#endif

示例用法,避免不必要的格式更改通知

#include "blockSig.h"

void ConsoleEdit::selectionChanged()
{
    blockSig bs(this);

    foreach (ExtraSelection s, extraSelections())
        s.cursor.setCharFormat(s.format);
    extraSelections().clear();

    ...
}

【讨论】:

  • 感谢您的建议。不适用于此特定问题,但这是一个有用的想法。
猜你喜欢
  • 2011-05-23
  • 2022-09-23
  • 2020-10-02
  • 1970-01-01
  • 2023-03-12
  • 2017-02-22
  • 2015-01-28
  • 1970-01-01
  • 2020-03-25
相关资源
最近更新 更多