I'm building a windows program which shall have controls for 64bit numeric values. these controls shall be switchable to be signed or unsigned.
I found two controls:
"Spin Box"(int32) and "Double Spin Box"(double)
with double I'd be able to cover the range but it can't handle the precision.
Is there a way to change the data type of these controls?
Is it possible to create an own control which can handle signed and unsigned 64bit values?
Is it possible to create a 128bit Spin box?
The only work around I can see right now is in using a string control and manually convert to an INT64 or UINT64 but I'm not very happy with this solution
Any other Ideas?
I'm on QT 4.7.4 and VS2010 with C++
thx
You can derive QAbstractSpinBox and reimplement at least the virtual functions stepBy, stepEnabled and possibly validate() and fixup() for the input validation.
I don't use fixup function. See code of my Сustom QSpinBox.
class QLongLongSpinBox derived from QAbstractSpinBox
Don't forget call
setMaximum(std::numeric_limits<qlonglong>::max());
setMinimum(std::numeric_limits<qlonglong>::min());
after creating QLongLongSpinBox.
see qlonglongspinbox.h file:
#include <QtWidgets/QWidget>
#include <QtWidgets/QAbstractSpinBox>
#include <QtWidgets/QLineEdit>
class QLongLongSpinBoxPrivate;
class Q_WIDGETS_EXPORT QLongLongSpinBox : public QAbstractSpinBox
{
Q_OBJECT
Q_PROPERTY(qlonglong minimum READ minimum WRITE setMinimum)
Q_PROPERTY(qlonglong maximum READ maximum WRITE setMaximum)
Q_PROPERTY(qlonglong value READ value WRITE setValue NOTIFY valueChanged USER true)
qlonglong m_minimum;
qlonglong m_maximum;
qlonglong m_value;
public:
explicit QLongLongSpinBox(QWidget *parent = 0)
{
connect(lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onEditFinished()));
};
~QLongLongSpinBox() {};
qlonglong value() const
{
return m_value;
};
qlonglong minimum() const
{
return m_minimum;
};
void setMinimum(qlonglong min)
{
m_minimum = min;
}
qlonglong maximum() const
{
return m_maximum;
};
void setMaximum(qlonglong max)
{
m_maximum = max;
}
void setRange(qlonglong min, qlonglong max)
{
setMinimum(min);
setMaximum(max);
}
virtual void stepBy(int steps)
{
auto new_value = m_value;
if (steps < 0 && new_value + steps > new_value) {
new_value = std::numeric_limits<qlonglong>::min();
}
else if (steps > 0 && new_value + steps < new_value) {
new_value = std::numeric_limits<qlonglong>::max();
}
else {
new_value += steps;
}
lineEdit()->setText(textFromValue(new_value));
setValue(new_value);
}
protected:
//bool event(QEvent *event);
virtual QValidator::State validate(QString &input, int &pos) const
{
bool ok;
qlonglong val = input.toLongLong(&ok);
if (!ok)
return QValidator::Invalid;
if (val < m_minimum || val > m_maximum)
return QValidator::Invalid;
return QValidator::Acceptable;
}
virtual qlonglong valueFromText(const QString &text) const
{
return text.toLongLong();
}
virtual QString textFromValue(qlonglong val) const
{
return QString::number(val);
}
//virtual void fixup(QString &str) const;
virtual QAbstractSpinBox::StepEnabled stepEnabled() const
{
return StepUpEnabled | StepDownEnabled;
}
public Q_SLOTS:
void setValue(qlonglong val)
{
if (m_value != val) {
lineEdit()->setText(textFromValue(val));
m_value = val;
}
}
void onEditFinished()
{
QString input = lineEdit()->text();
int pos = 0;
if (QValidator::Acceptable == validate(input, pos))
setValue(valueFromText(input));
else
lineEdit()->setText(textFromValue(m_value));
}
Q_SIGNALS:
void valueChanged(qlonglong v);
private:
Q_DISABLE_COPY(QLongLongSpinBox)
Q_DECLARE_PRIVATE(QLongLongSpinBox)
};
To use you custom class (Widget) it in Qt Creator:
create QWidget widget
List item
select Promote to.. in widget menu
New Promoted Class:
QWigdet
Promoted class name QLongLongSpinBox
Header file: write qlonglongspinbox.h
Promote
select Promote to QLongLongSpinBox
save
You can see
<item>
<widget class="QLongLongSpinBox" name="value_integer" native="true"/>
</item>
and:
<customwidgets>
<customwidget>
<class>QLongLongSpinBox</class>
<extends>QWidget</extends>
<header>qlonglongspinbox.h</header>
<container>1</container>
</customwidget>
</customwidgets>
in *.ui file
in ui_*.h generating file you see you class:
#include "qlonglongspinbox.h"
QLongLongSpinBox *object_name;
value_integer = new QLongLongSpinBox(YourWidgetName);
value_integer->setObjectName(QStringLiteral("value_integer"));
verticalLayout->addWidget(value_integer);
Just for the sake of completeness: every time you run into a problem like this, remember that (in case everything else fails) you can just download the Qt source code and make your own QSpinBox64 or QSpinBox128 class in a matter of minutes by modifying the needed parts.
Related
I have a group of custom widgets that I am integrating into Qt designer and when I attempt to build it, it throws LNK2005, LNK2019, and a LNK1120. It seeems to be focusing around my QtMaterialFabPlugin file so I will provide the example code based upon that. It also basically says that every function of QtMaterialFabPlugin is already defined in the corresponding .obj file. Here is my relevant code, and any help on this is greatly appreciated.
QtMaterialFabPlugin.h:
#ifndef QTMATERIALFABPLUGIN_H
#define QTMATERIALFABPLUGIN_H
#include <QDesignerCustomWidgetInterface>
class QtMaterialFabPlugin : public QObject, public QDesignerCustomWidgetInterface
{
Q_OBJECT
Q_INTERFACES(QDesignerCustomWidgetInterface)
public:
QtMaterialFabPlugin(QObject *parent = 0);
bool isContainer() const;
bool isInitialized() const;
QIcon icon() const;
QString domXml() const;
QString group() const;
QString includeFile() const;
QString name() const;
QString toolTip() const;
QString whatsThis() const;
QWidget *createWidget(QWidget *parent);
void initialize(QDesignerFormEditorInterface *core);
private:
bool m_initialized;
};
#endif
QtMaterialFabPlugin.cpp:
#include "qtmaterialfab.h"
#include "qtmaterialfabplugin.h"
#include <QtPlugin>
QtMaterialFabPlugin::QtMaterialFabPlugin(QObject* parent) : QObject(parent) {
m_initialized = false;
}
void QtMaterialFabPlugin::initialize(QDesignerFormEditorInterface*) {
if (m_initialized) return;
m_initialized = true;
}
bool QtMaterialFabPlugin::isInitialized() const { return m_initialized; }
QWidget* QtMaterialFabPlugin::createWidget(QWidget* parent) {
return new QtMaterialFab(parent);
}
QString QtMaterialFabPlugin::name() const {
return QLatin1String("QtMaterialFab");
}
QString QtMaterialFabPlugin::group() const {
return QLatin1String("Material Widgets");
}
QIcon QtMaterialFabPlugin::icon() const { return QIcon(); }
QString QtMaterialFabPlugin::toolTip() const { return QLatin1String(""); }
QString QtMaterialFabPlugin::whatsThis() const { return QLatin1String(""); }
bool QtMaterialFabPlugin::isContainer() const { return false; }
QString QtMaterialFabPlugin::domXml() const {
return QLatin1String(
"<widget class=\"QtMaterialFab\" name=\"qtMaterialFab\">\n<widget>\n");
}
QString QtMaterialFabPlugin::includeFile() const {
return QLatin1String("qtmaterialfab.h");
}
Material-Widgets.pro:
CONFIG += plugin debug_and_release
TARGET = $$qtLibraryTarget(qtmaterialwidgetsplugin)
TEMPLATE =
HEADERS = qtmaterialappbarplugin.h qtmaterialautocompleteplugin.h qtmaterialavatarplugin.h qtmaterialbadgeplugin.h qtmaterialcheckboxplugin.h qtmaterialcircularprogressplugin.h qtmaterialdialogplugin.h qtmaterialdrawerplugin.h qtmaterialfabplugin.h qtmaterialflatbuttonplugin.h qtmaterialiconbuttonplugin.h qtmateriallistplugin.h qtmateriallistitemplugin.h qtmaterialmenuplugin.h qtmaterialprogressplugin.h qtmaterialradiobuttonplugin.h qtmaterialraisedbuttonplugin.h qtmaterialscrollbarplugin.h qtmaterialsliderplugin.h qtmaterialsnackbarplugin.h qtmaterialtableplugin.h qtmaterialtabsplugin.h qtmaterialtextfieldplugin.h qtmaterialtoggleplugin.h qtmaterialwidgets.h
SOURCES = qtmaterialsliderplugin.cpp qtmaterialappbarplugin.cpp qtmaterialautocompleteplugin.cpp qtmaterialavatarplugin.cpp qtmaterialbadgeplugin.cpp qtmaterialcheckboxplugin.cpp qtmaterialcircularprogressplugin.cpp qtmaterialdialogplugin.cpp qtmaterialdrawerplugin.cpp qtmaterialfabplugin.cpp qtmaterialflatbuttonplugin.cpp qtmaterialiconbuttonplugin.cpp qtmateriallistplugin.cpp qtmateriallistitemplugin.cpp qtmaterialmenuplugin.cpp qtmaterialprogressplugin.cpp qtmaterialradiobuttonplugin.cpp qtmaterialraisedbuttonplugin.cpp qtmaterialscrollbarplugin.cpp qtmaterialsnackbarplugin.cpp qtmaterialtableplugin.cpp qtmaterialtabsplugin.cpp qtmaterialtextfieldplugin.cpp qtmaterialtoggleplugin.cpp qtmaterialwidgets.cpp
RESOURCES = icons.qrc
LIBS += -L.
greaterThan(QT_MAJOR_VERSION, 4) {
QT += designer
} else {
CONFIG += designer
}
target.path = $$[QT_INSTALL_PLUGINS]/designer
INSTALLS += target
include(qtmaterialextrafiles.pri)
include(qtmaterialraisedbutton.pri)
include(qtmateriallist.pri)
include(qtmaterialradiobutton.pri)
include(qtmaterialslider.pri)
include(qtmaterialtextfield.pri)
include(qtmaterialtoggle.pri)
include(qtmaterialdialog.pri)
include(qtmaterialtable.pri)
include(qtmaterialautocomplete.pri)
include(qtmaterialbadge.pri)
include(qtmaterialcheckbox.pri)
include(qtmaterialavatar.pri)
include(qtmaterialcircularprogress.pri)
include(qtmaterialappbar.pri)
include(qtmaterialfab.pri)
include(qtmaterialdrawer.pri)
include(qtmaterialsnackbar.pri)
include(qtmaterialmenu.pri)
include(qtmateriallistitem.pri)
include(qtmaterialflatbutton.pri)
include(qtmaterialtabs.pri)
include(qtmaterialiconbutton.pri)
include(qtmaterialscrollbar.pri)
include(qtmaterialprogress.pri)
Whoops, I just had to add the
TEMPLATE = lib
to the .pro file.
I am building a C++ GUI application on QT Creator.
I changed the location to Portuguese/Brazil, now only comma is the decimal separator.
I need the QDoubleSpinBox to get as decimal separator dot and comma.
Officialy comma is the separator in Portuguese, but some keyboard only have points in the numeric part.
Please help,
subClass QDoubleSpinBox and reimplement the virtual method validate
full solution here :
customSpinBox.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QRegExpValidator>
#include <QDoubleSpinBox>
class CustomSpinBox : public QDoubleSpinBox {
Q_OBJECT
public:
explicit CustomSpinBox(QWidget* parent =0);
virtual QValidator::State validate(QString & text, int & pos) const;
private:
QRegExpValidator* validator;
};
#endif // WIDGET_H
customSpinBox.cpp
CustomSpinBox::CustomSpinBox(QWidget *parent):QDoubleSpinBox(parent),
validator(new QRegExpValidator(this))
{
validator->setRegExp(QRegExp("\\d{1,}(?:[,.]{1})\\d*"));
}
QValidator::State CustomSpinBox::validate(QString &text, int &pos) const
{
return validator->validate(text,pos);
}
I tried to converted the solution from basslo to Qt 6.0 but it failed to accept integer numbers. The following solution works fine for me with Qt 6.0. Also it did not work, wehen a suffix is set for the spin with i.e spinBox->setSuffix("mm");
My current solution below:
class CRelaxedDoubleSpinBox : public QDoubleSpinBox {
Q_OBJECT
bool doConvert = false;
QString decimalStr;
public:
explicit CRelaxedDoubleSpinBox(QWidget* parent =0, double minVal = -100, double maxVal = 100.) : QDoubleSpinBox(parent)
{
// setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
setMinimum(minVal);
setMaximum(maxVal);
setAlignment(Qt::AlignRight);
QLocale curLocale;
decimalStr = curLocale.decimalPoint();
doConvert = curLocale.decimalPoint() != ".";
}
virtual QValidator::State validate(QString & text, int & pos) const
{
QString s(text);
if(doConvert)
s = s.replace(".", decimalStr);
return QDoubleSpinBox::validate(s,pos);
}
double valueFromText(const QString& text) const
{
QString s(text);
if(doConvert)
s = s.replace(".", decimalStr);
return QDoubleSpinBox::valueFromText(s);
}
};
You can subclass QDoubleSpinBox and reimplement the validate method to accept both the dot and the comma as the decimal separator. I think you can get by with just adding a special check when the input is a period and allow it to be accepted (provided there are no other periods or commas in the string), but otherwise call the base class implementation. I haven't compiled or tested this, but I think this is pretty close:
MyDoubleSpinBox::validate (QString &input, int &pos)
{
if (input == ".")
{
return (text ().contains (".") || text ().contains (",")) ? QValidator::Invalid : QValidator::Acceptable;
}
return QDoubleSpinBox::validate (input, pos);
}
I'm using PySide6 and I adapted to the Python language the wonderful solution provided by #RED SOFT ADAIR to Python:
from PySide6.QtWidgets import QDoubleSpinBox,
class CustomDoubleSpinbox(QDoubleSpinBox):
def validate(self, text: str, pos: int) -> object:
text = text.replace(".", ",")
return QDoubleSpinBox.validate(self, text, pos)
def valueFromText(self, text: str) -> float:
text = text.replace(",", ".")
return float(text)
Here it is in case anyone ended up here in a similar situation.
Solution given by basslo does not work for me. I also need to reimplement the valueFromText method. Otherwise, when I press the enter key in the DoubleSpinBox, the value is set to 0.
Here is the class
doublespinboxwithcommasandpoints.h
#ifndef DOUBLESPINBOWITHCOMMASANDPOINTS_H
#define DOUBLESPINBOWITHCOMMASANDPOINTS_H
#include <QDoubleSpinBox>
#include <QRegularExpressionValidator>
class DoubleSpinBoxWithCommasAndPoints : public QDoubleSpinBox
{
Q_OBJECT
public:
explicit DoubleSpinBoxWithCommasAndPoints(QWidget* parent = nullptr);
virtual ~DoubleSpinBoxWithCommasAndPoints();
QValidator::State validate(QString & text, int & pos) const override;
qreal valueFromText(const QString &text) const override;
private:
QRegularExpressionValidator* m_validator;
QString current_suffix;
};
#endif // DOUBLESPINBOWITHCOMMASANDPOINTS_H
doublespinboxwithcommasandpoints.cpp
#include "doublespinboxwithcommasandpoints.h"
DoubleSpinBoxWithCommasAndPoints::DoubleSpinBoxWithCommasAndPoints(QWidget *parent)
: QDoubleSpinBox(parent)
, m_validator(nullptr)
, current_suffix(QString())
{
// validate positive or negative number written with "." or ","
// and that may have a suffix at the end
// also match empty string "(?![\\s\\S]\r\n)" to allow user to clear the whole field
const QString regex = QStringLiteral("((?![\\s\\S]\r\n)|-?\\d{1,}(?:[,.]{1})?\\d*)");
m_validator = new QRegularExpressionValidator(QRegularExpression(regex), this);
// check if a suffix has been added
connect(this, &DoubleSpinBoxWithCommasAndPoints::textChanged,
[this](){
if(!suffix().isEmpty()) {
if(current_suffix.localeAwareCompare(suffix()) == 0)
return;
else
current_suffix = suffix();
}
QString previous_regex = m_validator->regularExpression().pattern();
// remove the ending ")"
previous_regex.chop(1);
QString new_regex = previous_regex +
QStringLiteral("(?:") + suffix() + QStringLiteral(")?)");
m_validator->setRegularExpression(QRegularExpression(new_regex));
});
}
DoubleSpinBoxWithCommasAndPoints::~DoubleSpinBoxWithCommasAndPoints()
{
}
QValidator::State DoubleSpinBoxWithCommasAndPoints::validate(QString &text, int &pos) const
{
return m_validator->validate(text, pos);
}
qreal DoubleSpinBoxWithCommasAndPoints::valueFromText(const QString &text) const
{
QString temp = text;
temp.replace(QStringLiteral(","), QStringLiteral(".")); // replace comma with dot before toDouble()
temp.remove(suffix()); // remove suffix at the end of the value
return temp.toDouble();
}
Few points:
this code works with Qt6
the regular expression accepts negative numbers as well
the regular expression accepts numbers without comma/point
the regular expression supports suffix (code can be adapted to also support prefix)
the regular expression matchs empty string which allows users to clear the whole field
My application consists of many Lists that I display in QML-ListViews by using QAbstractListModel derived model-classes. It's always the same, with the difference of the Item-Type. That's why I want to know how to build a class-template for this approach.
I figured out, that it is not possible to use the Q_OBJECT-Macro in a class-template. That's why my GenericListModel consists of two part.
1. GenericListModelData
The first part is the Model itself that derives from QAbstractListModel and implements the basic functions data(), rowCount() and roleNames().
2. GenericListModel
The second part is the class-template that is used as a wrapper to provide functions similar to a QListView.
If you have any suggestions or questions please let me know. It would be really nice to improve this solution.
I uploaded the full sourcecode here:
https://github.com/sebabebibobu/QGenericListModel/
1. GenericListModelData
QVariant GenericListModelData::data(const QModelIndex &index, int role) const
{
QObject *item = m_itemList.at(index.row());
return item->property(item->metaObject()->property(role).name());
}
/*
* Returns the number of items attached to the list.
*/
int GenericListModelData::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_itemList.size();
}
/*
* Generates a hash out of QMetaObject property-index and property-name.
*/
QHash<int, QByteArray> GenericListModelData::roleNames() const
{
QHash<int, QByteArray> roles;
if (!m_itemList.isEmpty()) {
for(int i = 0; i < m_itemList.at(0)->metaObject()->propertyCount(); i++) {
roles[i] = m_itemList.at(0)->metaObject()->property(i).name();
}
}
return roles;
}
/*
* Append Item to List.
*/
void GenericListModelData::appendItem(QObject *item)
{
/* map the notify()-signal-index with the property-index when the first item get's inserted */
if (m_itemList.isEmpty()) {
for(int i = 0; i < item->metaObject()->propertyCount(); i++) {
m_propertySignalIndexHash.insert(item->metaObject()->property(i).notifySignalIndex(), i);
}
}
/* connect each notify()-signals to the onDataChanged()-slot which call's the dataChanged()-signal */
for(int i = 0; i < item->metaObject()->propertyCount(); i++) {
connect(item, "2" + item->metaObject()->property(i).notifySignal().methodSignature(), this, SLOT(onDataChanged()));
}
/* finally append the item the list */
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_itemList.append(item);
endInsertRows();
}
/*
* Helper-Slot that emit's the dataChanged()-signal of QAbstractListModel.
*/
void GenericListModelData::onDataChanged()
{
QModelIndex index = createIndex(m_itemList.indexOf(sender()),0);
QVector<int> roles;
roles.append(m_propertySignalIndexHash.value(senderSignalIndex()));
emit dataChanged(index, index, roles);
}
2. GenericListModel
template <typename T>
class GenericListModel : public GenericListModelData
{
public:
explicit GenericListModel(QObject *parent) : GenericListModelData(parent) {
}
void append(T *item) {
appendItem(item);
}
T *at(int i) {
return qobject_cast<T *>(m_itemList.at(i));
}
};
Update 01.05.2016
GrecKo posted in the comments, that a project like mine already exists. That's why I decided to share the link of this project here too:
http://gitlab.unique-conception.org/qt-qml-tricks/qt-qml-models
I would like to build up dialog same as Qt Creator "Options" tab that left side page titles with scroll bar and detailed page on the right side.
It would be really helpful if there were code samples or sample applications for reference.
Qt Creator Source Code
Qt Creator has it source code both in Gitorious and in GitHub. But because Qt Creator is such a large and complex project, it can be overwhelming finding its sub parts.
The Github version is very searchable. It ends up that the source related to the nice options page in Qt Creator uses the IOptionsPage as the base class for any of the pages that show up in the Options dialog.
https://github.com/qtproject/qt-creator/search?utf8=%E2%9C%93&q=ioptionspage&type=Code
The ioptionspage.cpp has all the comments explaining the purpose of the different slots.
https://github.com/qtproject/qt-creator/blob/9926fc2ab12ccaa02b7f03b416c54cd58ef30b31/src/plugins/coreplugin/dialogs/ioptionspage.cpp
Basically for Qt Creators options page, it has an interface that is used by several different sub modules.
https://github.com/qtproject/qt-creator/blob/9926fc2ab12ccaa02b7f03b416c54cd58ef30b31/src/plugins/coreplugin/dialogs/ioptionspage.h
#ifndef IOPTIONSPAGE_H
#define IOPTIONSPAGE_H
#include <coreplugin/id.h>
#include <QIcon>
#include <QObject>
#include <QStringList>
namespace Core {
class CORE_EXPORT IOptionsPage : public QObject
{
Q_OBJECT
public:
IOptionsPage(QObject *parent = 0);
virtual ~IOptionsPage();
Id id() const { return m_id; }
QString displayName() const { return m_displayName; }
Id category() const { return m_category; }
QString displayCategory() const { return m_displayCategory; }
QIcon categoryIcon() const { return QIcon(m_categoryIcon); }
virtual bool matches(const QString &searchKeyWord) const;
virtual QWidget *widget() = 0;
virtual void apply() = 0;
virtual void finish() = 0;
protected:
void setId(Id id) { m_id = id; }
void setDisplayName(const QString &displayName) { m_displayName = displayName; }
void setCategory(Id category) { m_category = category; }
void setDisplayCategory(const QString &displayCategory) { m_displayCategory = displayCategory; }
void setCategoryIcon(const QString &categoryIcon) { m_categoryIcon = categoryIcon; }
Id m_id;
Id m_category;
QString m_displayName;
QString m_displayCategory;
QString m_categoryIcon;
mutable bool m_keywordsInitialized;
mutable QStringList m_keywords;
};
/*
Alternative way for providing option pages instead of adding IOptionsPage
objects into the plugin manager pool. Should only be used if creation of the
actual option pages is not possible or too expensive at Qt Creator startup.
(Like the designer integration, which needs to initialize designer plugins
before the options pages get available.)
*/
class CORE_EXPORT IOptionsPageProvider : public QObject
{
Q_OBJECT
public:
IOptionsPageProvider(QObject *parent = 0) : QObject(parent) {}
Id category() const { return m_category; }
QString displayCategory() const { return m_displayCategory; }
QIcon categoryIcon() const { return QIcon(m_categoryIcon); }
virtual QList<IOptionsPage *> pages() const = 0;
virtual bool matches(const QString & /* searchKeyWord*/) const = 0;
protected:
void setCategory(Id category) { m_category = category; }
void setDisplayCategory(const QString &displayCategory) { m_displayCategory = displayCategory; }
void setCategoryIcon(const QString &categoryIcon) { m_categoryIcon = categoryIcon; }
Id m_category;
QString m_displayCategory;
QString m_categoryIcon;
};
} // namespace Core
#endif // IOPTIONSPAGE_H
The search box uses an index the all the titles/labels of the children of each options page that gets added.
bool Core::IOptionsPage::matches(const QString &searchKeyWord) const
{
if (!m_keywordsInitialized) {
IOptionsPage *that = const_cast<IOptionsPage *>(this);
QWidget *widget = that->widget();
if (!widget)
return false;
// find common subwidgets
foreach (const QLabel *label, widget->findChildren<QLabel *>())
m_keywords << label->text();
foreach (const QCheckBox *checkbox, widget->findChildren<QCheckBox *>())
m_keywords << checkbox->text();
foreach (const QPushButton *pushButton, widget->findChildren<QPushButton *>())
m_keywords << pushButton->text();
foreach (const QGroupBox *groupBox, widget->findChildren<QGroupBox *>())
m_keywords << groupBox->title();
// clean up accelerators
QMutableStringListIterator it(m_keywords);
while (it.hasNext())
it.next().remove(QLatin1Char('&'));
m_keywordsInitialized = true;
}
foreach (const QString &keyword, m_keywords)
if (keyword.contains(searchKeyWord, Qt::CaseInsensitive))
return true;
return false;
}
Finding the rest of the components of the original dialog may take some time, but it is doable.
Included Example
When in Qt Creator > Welcome (tab) > Examples, the best one for a complex settings dialog is probably:
Tab Dialog Example
http://doc.qt.io/qt-5/qtwidgets-dialogs-tabdialog-example.html
Persistent Settings
QSettings is probably the best bet for storing settings. Other options include XML, and JSON. Qt 5 has a great implementation of JSON.
Hope that helps.
I'm trying to write an OO menu system for a game, loosely based on the idea of a Model,View,Controller. In my app so far I've named the views "renderers" and the models are without a suffix. I created a generic menu class which stores the items of a menu, which are menu_item objects, and there is also a menu renderer class which creates renderers for each item and renders them. The problem is I'm not sure where to store the data and logic to do with where on the screen each item should be positioned, and how to check if it is being hovered over, etc. My original idea was to store and set a selected property on each menu item, which could be rendered differently by different views, but even then how to I deal with positioning the graphical elements that make up the button?
Code excerpts so far follow: (more code at https://gist.github.com/3422226)
/**
* Abstract menu model
*
* Menus have many items and have properties such as a title
*/
class menu {
protected:
std::string _title;
std::vector<menu_item*> _items;
public:
std::string get_title();
void set_title(std::string);
std::vector<menu_item*> get_items();
};
class menu_controller: public controller {
private:
menu* _menu;
public:
menu_controller(menu*);
virtual void update();
};
class menu_item {
protected:
std::string _title;
public:
menu_item(std::string title);
virtual ~menu_item();
std::string get_title();
};
class menu_renderer: public renderer {
private:
menu* _menu;
bitmap _background_bitmap;
static font _title_font;
std::map<menu_item*, menu_item_renderer*> _item_renderers;
public:
menu_renderer(menu*);
virtual void render();
};
font menu_renderer::_title_font = NULL;
menu_renderer::menu_renderer(menu* menu) {
_menu = menu;
_background_bitmap = ::load_bitmap("blackjack_menu_bg.jpg");
if (!_title_font)
_title_font = ::load_font("maven_pro_regular.ttf",48);
}
void menu_renderer::render() {
::draw_bitmap(_background_bitmap, 0, 0);
/* Draw the menu title */
const char* title = _menu->get_title().c_str();
int title_width = ::text_width(_title_font, title);
::draw_text(title, color_white, _title_font, screen_width() - title_width - 20, 20);
/* Render each menu item */
std::vector<menu_item*> items = _menu->get_items();
for (std::vector<menu_item*>::iterator it = items.begin(); it != items.end(); ++it) {
menu_item* item = *it;
if (!_item_renderers.count(item))
_item_renderers[item] = new menu_item_renderer(item, it - items.begin());
_item_renderers[item]->render();
}
}
class menu_item_renderer: public renderer {
private:
unsigned _order;
menu_item* _item;
static font _title_font;
public:
menu_item_renderer(menu_item*, unsigned);
virtual ~menu_item_renderer();
virtual void render();
};
font menu_item_renderer::_title_font = NULL;
menu_item_renderer::menu_item_renderer(menu_item* item, unsigned order) {
_item = item;
_order = order;
if (!_title_font)
_title_font = ::load_font("maven_pro_regular.ttf",24);
}
menu_item_renderer::~menu_item_renderer() {
// TODO Auto-generated destructor stub
}
void menu_item_renderer::render() {
const char* title = _item->get_title().c_str();
int title_width = ::text_width(_title_font, title);
unsigned y = 44 * _order + 20;
::fill_rectangle(color_red, 20, y, title_width + 40, 34);
::draw_text(title, color_white, _title_font, 30, y + 5);
}
Your Model class menu needs a add_view(menuview *v) and update() method.
Then you can delegate the update of your widget to the derived View (menu_renderer or a cli_menu_renderer).
The Controller needs to know the Model (as member), when the Controller runs (or executes a Command) and has to update the Model with a Setter (like m_menu_model->set_selected(item, state)) and the Model calls update() on Setters.
Your Controller menu_controller has a update method, there you could also ask for Input, like if (menuview->toggle_select()) m_menu_model->toggle_selected(); (which all menuviews have to implement) and invoke the setter, but thats a inflexible coupling of View and Controller (you could check MVC with the Command Pattern for a more advanced combination).
For the Position you can set member vars like int m_x, m_y, m_w, m_h.
But these members are specific to a View with GUI, so only the derived View needs them.
Then you could use these values to compare against mouse Positions and use a MouseOver Detection Method like this:
// View menu_item
bool menu_item::over()
{
if (::mouse_x > m_x
&& ::mouse_x < m_x + m_w
&& ::mouse_y > m_y
&& ::mouse_y < m_y + m_h) {
return true;
}
return false;
}
// update on gui menu item
bool menu_item::update()
{
if (over()) {
m_over = true;
}
else {
m_over = false;
}
// onclick for the idea
if ((::mouse_b & 1) && m_over) {
// here you could invoke a callback or fire event
m_selected = 1;
} else {
m_selected = 0;
}
return m_selected;
}
// update the command line interface menu item
bool cli_menu_item::update()
{
if ((::enterKeyPressed & 1) && m_selected) {
// here you could invoke a callback or fire event
m_selected = 1;
} else {
m_selected = 0;
}
return m_selected;
}
void menu_item_renderer::render() {
// update widgets
_item->update();
// ...
}
// Model
void menu::add_view(menuview *v) {
m_view=v;
}
void menu::update() {
if (m_view) m_view->update();
}
bool menu::set_selected(int item, int state) {
m_item[index]=state;
update();
}