2015-09-15 2 views
4

У меня есть файл ui с QProgressBar в QWidget. Более того, я создал свой пользовательский компонент индикатора выполнения, который наследуется от QProgressBar. В QT Designer я могу продвигать виджет QProgressBar в свой пользовательский виджет. Есть ли способ сделать это в файле cpp widget вместо использования QT Designer? Другими словами, есть ли способ программно продвинуть QWidget в другой пользовательский видже того же типа (вид morphing)?Программно продвигать QWidget

Вот пример:

class MyProgressBar : public QProgressBar 
{ 
    Q_OBJECT 

public: 
    explicit CmdProgressWidget(QWidget *parent = 0); 
    ~CmdProgressWidget(); 

    int myCustomFunction(); 
}; 

class MyWidgetWithProgress : public QWidget, public Ui::MyWidget 
{ 
    Q_OBJECT 

    public: 
     MyWidgetWithProgress (QWidget *parent = 0) {setupUi(this);} 
     ~MyWidgetWithProgress() {;} 

    inline int callMyCustomFunction() {progressBar->myCustomFunction();} 
}; 

Распространенный способ получить код int callMyCustomFunction() компиляции должен продвигать в QT Designer индикатор прогресса в виджете (QProgressBar) в мой пользовательский виджет MyProgressBar.

Назад к исходному вопросу: есть ли способ сделать это программно (например, в конструкторе MyWidgetWithProgress после setupUi(this);)?

+0

«в другой пользовательский виджет одного и того же типа» - последняя часть не имеет особого смысла. Если бы это был тот же ** тип, продвижение не было бы. Вы имеете в виду другой пользовательский тип виджетов, наследующий тип, от которого следует продвигать? Например, продвигайте экземпляр 'QProgressBar' в' MyProgressBar', который наследует 'QProgressBar'? – leemes

+1

Если я правильно вас понимаю, вы можете * заменить * виджет, который будет полностью продвинут. Вы не можете продвигать экземпляр объекта впоследствии подтипа, что невозможно самому C++ и не имеет ничего общего с Qt. Таким образом, возможным решением было бы программно создать новый виджет нового типа и скопировать свойства поверх старого на новый объект (это можно сделать в специальном конструкторе вашего настраиваемого типа виджетов) и, наконец, заменить его в виджетах дерева и макета. – leemes

+1

Говоря это, иногда проще просто разместить «конструктор» в дизайнере, в котором вы добавляете свой пользовательский виджет во время выполнения в качестве дочернего элемента (с простым макетом без полей и т. Д., Так что ребенок полностью заполняет местозаполнитель) , Но тогда фактический виджет вообще отсутствует в дизайнере, что делает невозможным редактирование некоторых свойств виджета для добавления непосредственно в конструктор, но обычно это не проблема. Эта процедура заключается в том, как я делал это большую часть времени, когда я был в такой ситуации. – leemes

ответ

1

Есть ли способ сделать это в файле cpp виджета вместо использования QT Designer?

Вообще говоря: нет. Qt Designer создает файл Xyz.ui, простое описание XML дерева объектов и свойств объекта. Генератор кода uic принимает этот файл .ui и создает ui_Xyz.h. Типы его членов установлены: вы не можете программно их изменять, так же, как вы не можете программно изменить тип любого другого члена.

Итак, используйте правильный тип объекта в конструкторе. Если вы продвинете некоторый базовый тип (скажем QProgressBar) на свой собственный производный тип, то setupUi создаст экземпляр вашего типа. Таким образом, вся проблема исчезает.

Но вам не нужно изменять файл .ui с помощью конструктора. Вы можете тривиально изменить его вручную, чтобы продвигать нужные вам виджеты. Предположим, что мы начнем с простой виджет, который имеет прогресс бар в нем:

<?xml version="1.0" encoding="UTF-8"?> 
<ui version="4.0"> 
<class>Form</class> 
<widget class="QWidget" name="Form"> 
    <property name="geometry"> 
    <rect> 
    <x>0</x> 
    <y>0</y> 
    <width>256</width> 
    <height>40</height> 
    </rect> 
    </property> 
    <layout class="QGridLayout" name="gridLayout"> 
    <item row="0" column="0"> 
    <widget class="QProgressBar" name="placeholder"> 
    <property name="value"> 
     <number>24</number> 
    </property> 
    </widget> 
    </item> 
    </layout> 
</widget> 
<resources/> 
<connections/> 
</ui> 

Чтобы изменить тип progressBar элемента, вы должны сделать два изменения в файл XML.Во-первых, изменить тип самого элемента:

<widget class="MyProgressBar" name="placeholder"> 
<property name="value"> 
    <number>24</number> 
</property> 
</widget> 

Добавьте тип к <customwidgets> пункта:

<customwidgets> 
<customwidget> 
    <class>MyProgressBar</class> 
    <extends>QProgressBar</extends> 
    <header>myprogressbar.h</header> 
</customwidget> 
</customwidgets> 

Если вы намерены, в сущности, есть неправильный .ui файл, вы можете сделать замена виджета во время выполнения.

Есть два основных аспекта этого:

  1. ли вы на самом деле нужен пользовательский тип?

    Во многих случаях вы можете делать все, не используя базовый виджет. Не имеет значения для вас, трудно сказать: я не понимаю, почему вы не можете использовать правильный тип (MyProgressBar) в своем файле .ui.

    // Would-Be Derived Class 
    class MyProgressBar : public QProgressBar { 
        int m_var; 
    protected: 
        void paintEvent(QPaintEvent * ev) { 
        QProgressBar::paintEvent(event(ev)); // let the base class paint itself 
        QPainter p(this); 
        // do some overpainting, etc. 
        } 
    public: 
        void doSomething() { 
        m_var = 3; 
        } 
    }; 
    
    // Do the same using the base class instead: 
    void doSomething(QProgressBar * bar) { 
        bar.setProperty("m_var", 3); 
    } 
    
    void paintEvent(QWidget * w, QPaintEvent * ev) { 
        w->event(ev); // let the base class paint itself 
        QPainter p(w); 
        // do some overpainting, etc. 
    } 
    
    struct Painter : public QObject { 
        bool eventFilter(QObject * obj, QEvent * ev) { 
        if (obj->isWidgetType() && ev->type() == QEvent::Paint) 
         paintEvent(static_cast<QWidget*>(obj), static_cast<QPaintEvent*>(ev)); 
        return QObject::eventFilter(obj, ev); 
        } 
    } 
    
    QProgressBar bar; 
    bar.installEventFilter(new Painter(&bar)); 
    
  2. Выполнение замены.

    Вам необходим доступ к виджету с помощью указателя/ссылки/значения правильного типа. В идеале, сохраните новый виджет непосредственно по значению.

    class Form : public QWidget, private Ui::Form { 
        MyProgressBar m_bar; 
        ... 
    } 
    

    Затем замените виджет-заполнитель в своем расположении экземпляром соответствующего типа.

    void replace(QWidget * & old, QWidget * replacement) { 
        auto layout = old->parent()->layout(); 
        // name the new widget the same 
        replacement->setObjectName(old->objectName()); 
        // swap the widgets and delete the layout item 
        delete layout->replaceWidget(old, replacement); 
        // delete the old widget 
        delete old; 
        // don't leave a dangling pointer 
        old = nullptr; 
    } 
    
    Form:: Form(QWidget * parent) : 
        QWidget(parent) 
    { 
        setupUi(this); 
        replace(placeholder, &m_bar); 
        // you have to manually connect slots for the m_bar widget 
    } 
    
1

Операция «продвигать» в Qt Designer изменяет фактический тип виджета и использует продвинутый класс виджетов в файле .cpp. Компилятор никогда не видит, что имя оригинального, непромотируемого класса является типом виджета. В C++ вам придется сделать то же самое: измените тип виджета на так называемый «продвинутый» тип.

Вы могли бы, если бы у вас был произвольный QWidget*, введите его в свой «продвинутый» тип, используя qobject_cast<>(). Это только сработало бы, если бы вы знали, что указатель QWidget указал на экземпляр вашего «продвинутого» класса, иначе кастинг вернет NULL.

-1

Все, что вам нужно, может выглядеть следующим образом:

QProgressBar* temp = new MyProgressBar(m_widget, CALENDAR_DEL, 30); 
m_horizontalLayout->replaceWidget(m_prg, temp);//the most important function replaceWidget() 
delete m_prg;// 
m_prg = temp;//Qt will release children widgets finally, make sure m_prg point to the temp 
Смежные вопросы