List of spinboxes, displaying only values changed - c++

So, I have an extensive list of spinboxes (30) in one tab and a confirmation page on another tab.
How can I can display only the names and values of those above 0 in the confirmation page?
Not sure if it matters, I'm doing this in Qt.

If I were you, I would be writing something like this:
confirmationpage.cpp
#include <QString>
#include <QSpinBox>
#include <QList>
#include <QLabel>
...
void ConfirmationPage::displaySpinBoxNameValues()
{
QString myText;
// Get the spinboxes from your tab.
// Use pointer anywhere here if you use that
foreach (SpinBox spinbBox, SpinBoxList) {
if (spinBox.value() > 0) {
myText.append(QString("Name: ") + spinBox.text());
myText.append(QString("\tValue: ") + spinBox.value());
myText.append('\n');
}
}
if (myText.isEmpty())
myText.append("No QSpinBox has value greater than zero!\n");
// Could be a QLabel, etc.
myDisplayWidget.setText(myText);
}
...
You would need the following method documentations to understand the methods used for this:
QLabel text property
QLabel value property

You can obtain the list of spinboxes and iterate over them like:
QList<QSpinBox *> list = this->findChildren<QSpinBox *>();
foreach(QSpinBox *spin, list)
{
if(spin->value()>0)
{
QDebug()<< spin->objectName();
}
}
You can get the name of the object by objectName() if you have previously assigned names to your spinboxes by setObjectName(const QString &name) .

Related

Is there a method or a way to check whether a user has visited a certain tab page on a QTabWidget?

I have a QTabWidget on my application, so user can navigate through the tab pages by clicking on the title, I want to know when user open a tab page, whether he/she visited this page previously. In QWizard class there is a method hasVisitedPage() which does the exact same thing on a wizard, but I couldn't find a similar method in QTabWidget class. What I want to know is, whether there is a method to do this like in QWizard?
this is the similar method in QWizard class http://doc.qt.io/archives/qt-4.8/qwizard.html#hasVisitedPage
Currently I am using a QList to store the visited page indexes and each time when a user open a tabpage check whether QList contains the index of the opened page, I think it would be more easy if I had a method to check
What I want to know is, whether there is a method to do this like in QWizard?
Unfortunatelly, there is not.
Currently I am using a QList to store the visited page indexes and each time when a user open a tabpage check whether QList contains the index of the opened page
QWizard does the same, i.e. has a QList<int> history; attribute. So, in my opinion you are doing it the right way.
Take a look at the source code for more details. In particular, QWizardPrivate::switchToPage might be interesting to you, in order to give you an idea how it is done in QWizard, so you can check your own implementation against that and adapt it if necessary.
The history property is easy enough to add:
// https://github.com/KubaO/stackoverflown/tree/master/questions/tabwidget-history-52033092
#include <QtWidgets>
#include <array>
static const char kHistory[] = "history";
auto getHistory(const QTabWidget *w) {
return w->property(kHistory).value<QList<int>>();
}
void addHistory(QTabWidget *tabWidget) {
QObject::connect(tabWidget, &QTabWidget::currentChanged, [tabWidget](int index) {
if (index < 0) return;
auto history = getHistory(tabWidget);
history.removeAll(index);
history.append(index);
tabWidget->setProperty(kHistory, QVariant::fromValue(history));
});
if (tabWidget->currentIndex() >= 0)
tabWidget->setProperty(
kHistory, QVariant::fromValue(QList<int>() << tabWidget->currentIndex()));
}
bool hasVisitedPage(const QTabWidget *w, int index) {
return getHistory(w).contains(index);
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QWidget ui;
QVBoxLayout layout{&ui};
QTabWidget tabWidget;
QLabel history;
layout.addWidget(&tabWidget);
layout.addWidget(&history);
std::array<QLabel, 5> tabs;
for (auto &l : tabs) {
auto const n = &l - &tabs[0] + 1;
l.setText(QStringLiteral("Label on Page #%1").arg(n));
tabWidget.addTab(&l, QStringLiteral("Page #%1").arg(n));
}
addHistory(&tabWidget);
auto showHistory = [&] {
auto text = QStringLiteral("History: ");
for (auto i : tabWidget.property("history").value<QList<int>>())
text.append(QString::number(i + 1));
history.setText(text);
};
showHistory();
QObject::connect(&tabWidget, &QTabWidget::currentChanged, showHistory);
tabWidget.currentChanged(tabWidget.currentIndex());
ui.show();
return app.exec();
}

How to make the text of a QComboBox bold, but not the list items?

We have a longstanding convention in our UI that items are shown in bold when they have been changed but the change is not yet committed. Strangely, until now we haven't used any combo boxes, but I have a use for one now and need to implement this behaviour. So I need to programmatically bold (and later un-bold) the text displayed by a closed combo box. However, I don't want to bold the entire list of items in the pop-up. I could accept bolding the selected item in the list if that's easier.
I've seen lots of answers doing almost this, but usually trying to modify the list items rather than the button. I've tried variations on most of them; unfortunately I didn't keep records of what I tried. For what it's worth, my code currently looks like:
myCombo->setStyleSheet(
"QComboBox {font-weight: bold;} "
"QComboBox QAbstractItemView::item {font-weight: normal;}"
);
This turns the button bold, but also the list items. The same behaviour is seen when I apply the normal weight just to the QAbstractItemView without the ::item, and when I tried a different technique based on :open and :closed on the QComboBox.
I will say I'm fairly new to Qt. I am using Qt5 on Fedora 26, but will be deploying to CentOS 7.
It seems that setting the font-style in QComboBox overrides the view's (and it shouldn't, IMHO).
But, when I tried to explicitly set a view to the combo box, this way:
view = new QListView();
myCombo->setView(view);
the stylesheet posted by the OP suddenly worked.
By the way, the new view is different from the original (e.g. has a white background, etc) and I guess the OP isn't happy with that. One could go on styling it, of course, but one would rather prefer a ready to use view, with a consistent style.
Inspecting the default QComboBox view:
QComboBox * combo = new QComboBox();
qDebug() << combo->view();
yelds this:
QComboBoxListView(0x2091880)
So, there is a specific QComboBoxListView class, which is nowhere to be found in documentation and is defined in qcombobox_p.h, not a file one could include, really, but at least we can understand where the issue come from, in the viewOptions overridden method:
QStyleOptionViewItem option = QListView::viewOptions();
option.showDecorationSelected = true;
if (combo)
option.font = combo->font(); // <--- here
return option;
That combo is a private pointer to QComboBox, initialized in construction:
QComboBoxListView(QComboBox *cmb = 0) : combo(cmb) {}
which will always override the view options font with its own.
Let's have a copy of the QComboBoxListView class, edited and renamed:
comboitemview.h
#ifndef COMBOITEMVIEW_H
#define COMBOITEMVIEW_H
#include <QListView>
#include <QComboBox>
class ComboItemView : public QListView
{
Q_OBJECT
QComboBox * _box;
public:
ComboItemView(QComboBox *box);
protected:
void paintEvent(QPaintEvent *event);
void resizeEvent(QResizeEvent *event);
QStyleOptionViewItem viewOptions() const;
};
#endif // COMBOITEMVIEW_H
comboitemview.cpp
#include "comboitemview.h"
#include <QPaintEvent>
#include <QPainter>
ComboItemView::ComboItemView(QComboBox * box = 0) : _box(box){}
void ComboItemView::paintEvent(QPaintEvent *event)
{
if (_box)
{
QStyleOptionComboBox opt;
opt.initFrom(_box);
opt.editable = _box->isEditable();
if (_box->style()->styleHint(QStyle::SH_ComboBox_Popup, &opt, _box))
{
QStyleOptionMenuItem menuOpt;
menuOpt.initFrom(this);
menuOpt.palette = palette();
menuOpt.state = QStyle::State_None;
menuOpt.checkType = QStyleOptionMenuItem::NotCheckable;
menuOpt.menuRect = event->rect();
menuOpt.maxIconWidth = 0;
menuOpt.tabWidth = 0;
QPainter p(viewport());
_box->style()->drawControl(QStyle::CE_MenuEmptyArea, &menuOpt, &p, this);
}
}
QListView::paintEvent(event);
}
void ComboItemView::resizeEvent(QResizeEvent *event)
{
resizeContents(viewport()->width(), contentsSize().height());
QListView::resizeEvent(event);
}
QStyleOptionViewItem ComboItemView::viewOptions() const
{
QStyleOptionViewItem option = QListView::viewOptions();
option.showDecorationSelected = true;
return option;
}
And finally use it to style the view font:
myCombo->setView(new ComboItemView(myCombo));
myCombo->setStyleSheet(
"QComboBox {font-weight: bold;} "
"QComboBox QAbstractItemView {font-weight: normal;}"
);

Accessing the variables of a parent widget via a button

I'm trying to implement a default button. This button should access strings of the parent widget which is a dialog box which the button is found on. I pasted the relevant parts of the code below. What I want is to be able to place strings to their corresponding lineEdit's when default values is clicked. For example pulse_string goes to ui->pulse_freq and nr_pulsestring goes into ui->nr_pulses etc.
#include "settings.h"
#include "ui_settings.h"
#include <QLineEdit>
#include <QSlider>
#include <QSpinBox>
int pulse_freq = 25000;
int nr_pulses = 10;
int samp_freq = 150000;
int nr_samples = 2000;
int gain = 32;
int accumulate = 1;
int acq_start = 0;
Settings::Settings(QWidget *parent) :
QDialog(parent),
ui(new Ui::Settings)
{
QString pulse_string, nr_pulsestring, sampfreq_string, nr_samplestring, gain_string;
QString accumulate_string, acq_string;
}
Settings::~Settings()
{
delete ui;
}
void Settings::on_Default_Values_clicked()
{
ui->pulse_freq->setText("25000");
ui->nr_pulses->setText("10");
ui->samp_freq->setText("150000");
ui->nr_samples->setText("2000");
ui->gain->setText("32");
ui->accumulate->setText("1");
ui->acq_start->setText("0");
}
You can use something looking like follows:
ui->pulse_freq->setText(QString("%1").arg(pulse_freq));
Since it seems you are only using numbers it would be better using a spinbox to insert values, so you dont have to check if an input is a valid number, etc.

QTableView - Place pointer(highlight selection to the first row of list

I create own widget based on QTableView. It's something like file dialog (list). I want to act intuitively.
a) working with whole rows
b) indicator also worked with whole rows
c) using switched enter the lower level (subdirectory)
d) after run program or moving to a lower level cursor must be on the first row of the table (row 0)
And there is problem. I can not force the program to place the cursor on the first line.
I tried several methods, but none succeeded. setCurrentIndex. selectRow etc. Cursor is always somewhere else. Not highlighted, not on first line, but once it's on 10 position second on 4 position etc. It behaves unpredictably.
How can I do it?
Here my code is:
mFileBoxWidget::mFileBoxWidget(QWidget *parent) :
QTableView(parent)
,model(new QFileSystemModel())
{
this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->setShowGrid(false);
this->verticalHeader()->setVisible(false);
this->installEventFilter(this);
model->setReadOnly(true);
this->setModel(model);
this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch );
this->setColumnWidth(1,70);
this->setColumnWidth(2,70);
this->setColumnWidth(3,110);
this->setRootIndex(model->setRootPath("C://"));
this->setSelectionMode(QAbstractItemView::SingleSelection);
this->setSelectionBehavior(QAbstractItemView::SelectRows);
//this->selectRow(0); //Does not work - goto first row
//this->setCurrentIndes(Index); //Does not work - goto index x=0 y=0
}
Thank you with advance for all your responses.
Solved!
The problem is that the model is asynchronous. So reads the data in another thread. When I tried to set the index to the first line, still basically did not exist. The solution is, of course, to wait for loading the thread. At this point signal directoryLoaded(QString) is send. As a result, it is necessary to wait for the signal, and only then set index.
connect(myModel, SIGNAL(directoryLoaded(QString)), this, SLOT(onLoaded()));
void mFileBoxWidget::onLoaded()
{
QModelIndex index = myModel->index(myModel->rootPath());
this->setCurrentIndex(index.child(0, index.column()));
}
You shouldn't name your member variable model. QTableView has function model(), the compiler thinks this->model is meant to be this->model(), therefore you get the error you mentioned.
This is untested code, but I think something like this should work:
QModelIndex firstRow = QTableView::model()->index(0, 0);
QTableView::selectionModel()->select(firstRow,
QItemSelectionModel::ClearAndSelect |
QItemSelectionModel::Rows );
EDIT: (2013-06-19 06:12:58 UTC)
A simple (and ugly) workaround that worked so far for me is triggering a call to m_tableView->selectRow(0); from a QTimer.
Here's the sample code:
Header:
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QWidget>
class QTableView;
class QFileSystemModel;
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget(QWidget *parent = 0);
~MainWidget();
private:
void layoutWidgets();
QFileSystemModel *m_model;
QTableView *m_tableView;
private slots:
void selectFirstRow();
// for debugging only
void selectionChanged();
};
#endif // MAINWIDGET_H
Implementation:
#include "mainwidget.h"
#include <QTableView>
#include <QHBoxLayout>
#include <QFileSystemModel>
#include <QHeaderView>
#include <QTimer>
MainWidget::MainWidget(QWidget *parent)
: QWidget(parent)
{
m_tableView = new QTableView(this);
m_model = new QFileSystemModel(this);
m_model->setReadOnly(true);
m_tableView->setModel(m_model);
m_tableView->setRootIndex(m_model->setRootPath(QDir::homePath()));
m_tableView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_tableView->setShowGrid(false);
m_tableView->verticalHeader()->setVisible(false);
m_tableView->setColumnWidth(1,70);
m_tableView->setColumnWidth(2,70);
m_tableView-> setColumnWidth(3,110);
m_tableView->setSelectionMode(QAbstractItemView::SingleSelection);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
//m_tableView->->setSectionResizeMode(0, QHeaderView::Stretch ); // Qt 5?
layoutWidgets();
connect(m_tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged()) );
// This works
QTimer::singleShot(1000, this, SLOT(selectFirstRow()));
// Direct invocation - doesn't works
// selectFirstRow();
}
void MainWidget::layoutWidgets()
{
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(m_tableView);
setLayout(mainLayout);
setFixedSize(500,500);
}
void MainWidget::selectFirstRow()
{
m_tableView->selectRow(0);
}
void MainWidget::selectionChanged()
{
qDebug("Selection changed");
}
MainWidget::~MainWidget()
{}
The weird thing is, if QTimer::singleShot() needs to be triggered with a delay of at least ~25 ms., otherwise it wouldn't work in my system.
Here's the alternative, subclassing QTableView:
#include "mytableview.h"
#include <QFileSystemModel>
#include <QHeaderView>
#include <QTimer>
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
QFileSystemModel *myModel = new QFileSystemModel;
setModel(myModel);
setRootIndex(myModel->setRootPath(QDir::homePath()));
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setShowGrid(false);
verticalHeader()->setVisible(false);
//installEventFilter(this);
myModel->setReadOnly(true);
//setSectionResizeMode(0, QHeaderView::Stretch ); // Qt 5
setColumnWidth(1,70);
setColumnWidth(2,70);
setColumnWidth(3,110);
setSelectionMode(QAbstractItemView::SingleSelection);
setSelectionBehavior(QAbstractItemView::SelectRows);
QTimer::singleShot(100, this, SLOT(selectFirstRow()));
connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this, SLOT(selectionChanged()));
}
void MyTableView::selectFirstRow()
{
// qDebug("Selecting first row");
// QModelIndex firstRow = QTableView::model()->index(0,0);
// if(firstRow.isValid()){
// selectionModel()->select(firstRow, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows );
// }else{
// qDebug("Invalid index");
// }
selectRow(0);
}
void MyTableView::selectionChanged()
{
qDebug("Selection changed.");
}

QList<double> in QT with Visual Studio add in

I am working on creating a simple List Widget that displays "double" values when a "run" button is clicked. The widget contains 20 rows and 6 columns. Right now, I would just like for the values to all be the same number. I have the widget displaying how I want it, however, I am new to C++ and am not sure how to get the values to display in the widget when I click a pushbutton "run". Here is my code thus far:
qlistdouble.cpp
#include "qlistdouble.h"
#include <QList>
#include <QTableWidgetItem>
Qlistdouble::Qlistdouble(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
}
Qlistdouble::GetNumbers()
{
}
void Qlistdouble::MyClass(QList<double*> *slotString)
{
connect(ui.getNumber, SIGNAL(clicked()), this, SLOT(clear()));
for( int row = 0; row < 20; row++ )
{
for( int column = 0; column < 6; column++ )
{
slotString = new QList<double*>;
QTableWidgetItem *newItem = new QTableWidgetItem(tr("%1").arg(5));
ui.tableWidget_values->setItem(row, column, newItem);
}
}
}
qlistdouble.h
#ifndef QLISTDOUBLE_H
#define QLISTDOUBLE_H
#include <QtGui/QMainWindow>
#include "ui_qlistdouble.h"
class Qlistdouble : public QMainWindow
{
Q_OBJECT
public:
Qlistdouble(QWidget *parent = 0, Qt::WFlags flags = 0);
~Qlistdouble();
void MyClass(QList<double*> *slotString);
private:
Ui::QlistdoubleClass ui;
};
#endif // QLISTDOUBLE_H
I know that this is a simple question, but if someone could give me some suggestions on how to go about this, I would really appreciate it. Thanks in advance.
Displaying lists in Qt is usually achieved through QListView as a view and a QAbstractListModel as an underlying model. The list of model view examples is quite helpful.
I suggest looking at the source code of one of the simple example programs supplied with qt. essentially all you need to do is construct a Qapplication and your main window class, then call show on the main window and then exec() to start the event loop. I could write some from memory but the example code will be better.
Reading your comment, and using the very helpful link the other poster provided, I suggest starting with the trivial wizard example. It is a complete executable in a single file. You could put your own widget in one of the pages and calculate the numbers in when the page is shown.
http://qt-project.org/doc/qt-4.8/dialogs-trivialwizard.html
If this still seems too complex, then I suggest you may be trying to do too much as initial step. In this case I suggest instead writing a console application that prints the numbers to std::cout.