Есть ли способ сделать это в файле 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
файл, вы можете сделать замена виджета во время выполнения.
Есть два основных аспекта этого:
ли вы на самом деле нужен пользовательский тип?
Во многих случаях вы можете делать все, не используя базовый виджет. Не имеет значения для вас, трудно сказать: я не понимаю, почему вы не можете использовать правильный тип (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));
Выполнение замены.
Вам необходим доступ к виджету с помощью указателя/ссылки/значения правильного типа. В идеале, сохраните новый виджет непосредственно по значению.
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
}
«в другой пользовательский виджет одного и того же типа» - последняя часть не имеет особого смысла. Если бы это был тот же ** тип, продвижение не было бы. Вы имеете в виду другой пользовательский тип виджетов, наследующий тип, от которого следует продвигать? Например, продвигайте экземпляр 'QProgressBar' в' MyProgressBar', который наследует 'QProgressBar'? – leemes
Если я правильно вас понимаю, вы можете * заменить * виджет, который будет полностью продвинут. Вы не можете продвигать экземпляр объекта впоследствии подтипа, что невозможно самому C++ и не имеет ничего общего с Qt. Таким образом, возможным решением было бы программно создать новый виджет нового типа и скопировать свойства поверх старого на новый объект (это можно сделать в специальном конструкторе вашего настраиваемого типа виджетов) и, наконец, заменить его в виджетах дерева и макета. – leemes
Говоря это, иногда проще просто разместить «конструктор» в дизайнере, в котором вы добавляете свой пользовательский виджет во время выполнения в качестве дочернего элемента (с простым макетом без полей и т. Д., Так что ребенок полностью заполняет местозаполнитель) , Но тогда фактический виджет вообще отсутствует в дизайнере, что делает невозможным редактирование некоторых свойств виджета для добавления непосредственно в конструктор, но обычно это не проблема. Эта процедура заключается в том, как я делал это большую часть времени, когда я был в такой ситуации. – leemes