I have 1 QListWidget and 1 QStackedWidget. The QstackedWidget has three different widgets to be shown after selecting the entriesd on the QListWidget.
The problem: as I select the first choice nothing happens and nothing happens if I select the second choice, but when I select the last choice I see the widget on the QStackedWidget. This widget does not appartain to the third widget but it appartain to the first widget.
Signals of [QListWidget::currentRowChanged(C++ - QListWidget select first item) does not seem to be triggered correctly. Why is that happening? Basically seems to be triggered only the last choice instead all the others.
Below the snippet of code:
1 solution: works partially because out of three choices I can only see the last QWidget showing on the QStackedWidget:
OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::OptionsDialog)
{
ui->setupUi(this);
mVesPos = new VesselPosSystemWidget;
mSonar = new SonarForm;
mOutput = new OutputForm;
ui->stackedWidget->addWidget(mVesPos);
ui->stackedWidget->addWidget(mSonar);
ui->stackedWidget->addWidget(mOutput);
ui->horizontalLayout->addWidget(ui->stackedWidget);
setLayout(ui->horizontalLayout);
QObject::connect(ui->listWidget, &QListWidget::currentRowChanged,
ui->stackedWidget, &QStackedWidget::setCurrentIndex);
}
OptionsDialog::~OptionsDialog()
{
delete ui;
}
2 solution: works partially because out of three choices I can only see the last QWidget showing on the QStackedWidget. This solution was taken from official documentation of QStackedWidget:
OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::OptionsDialog)
{
ui->setupUi(this);
mVesPos = new VesselPosSystemWidget;
mSonar = new SonarForm;
mOutput = new OutputForm;
ui->stackedWidget->addWidget(mVesPos);
ui->stackedWidget->addWidget(mSonar);
ui->stackedWidget->addWidget(mOutput);
ui->horizontalLayout->addWidget(ui->stackedWidget);
setLayout(ui->horizontalLayout);
connect(ui->listWidget, QOverload<int>::of(&QListWidget::currentRowChanged),
ui->stackedWidget, &QStackedWidget::setCurrentIndex);
}
OptionsDialog::~OptionsDialog()
{
delete ui;
}
3 solution: same exact effect, only the third QWidget is shown:
OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::OptionsDialog)
{
ui->setupUi(this);
mVesPos = new VesselPosSystemWidget;
mSonar = new SonarForm;
mOutput = new OutputForm;
ui->stackedWidget->addWidget(mVesPos);
ui->stackedWidget->addWidget(mSonar);
ui->stackedWidget->addWidget(mOutput);
ui->horizontalLayout->addWidget(ui->stackedWidget);
setLayout(ui->horizontalLayout);
connect(ui->listWidget, &QListWidget::currentRowChanged,
[=](int index) { on_listWidget_currentRowChanged(index); });
}
OptionsDialog::~OptionsDialog()
{
delete ui;
}
void OptionsDialog::on_listWidget_currentRowChanged(int currentRow)
{
ui->stackedWidget->setCurrentIndex(currentRow);
}
I don't know what else to try to have the .ui forms switch after selcting the item in the QListWidget. Is there something I am missing? I tried all possible connect combinations but despite that I can only show the third choice.
I hope this could be useful for other users. I found a solution to this question. It was not easy and it required reading in depth the official documentation. Basically what was happening was that as I tried to select the proper QWidget on the QlistWidget, the selection was erroneously going to the incorrect form. I tried to
qDebug() << ui->stackedWidget->addWidget(mSonar);
qDebug() << ui->stackedWidget->addWidget(mOutput);
And was obtaining index 3,4,5. Which explains why I was only seeing the last index.
Now after long and in-depth reading of the documentation I found out about QStackedWidget::insertWidget relationships with all possible QWidget you want to link to the stack. It basically linking all the views to the form under the precise condition that what you are passing are QWidgets. So for example if you would like to link a QDialog to the QStackedWidget this is not allowed, because QStackedWidgets inherits QWidgets.
Therefore the solution was to insert the correct widget right from the beginning passing the proper index manually (in my case).
Code solution:
OptionsDialog::OptionsDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::OptionsDialog)
{
ui->setupUi(this);
mVesPos = new VesselPosSystemWidget;
mSonar = new SonarForm;
mOutput = new OutputForm;
ui->stackedWidget->insertWidget(0, mVesPos);
ui->stackedWidget->insertWidget(1, mSonar);
ui->stackedWidget->insertWidget(2, mOutput);
// This is how to link the choice according to the latest signals notation
connect(ui->listWidget, &QListWidget::currentRowChanged,
ui->stackedWidget, &QStackedWidget::setCurrentIndex);
}
The function can be found here and you can actually see, if you read carefully how the inheritance works. So again int QStackedWidget::insertWidget(int index, QWidget *widget) from official documentation solved the problem. I hope this could solve the problem for other users. :)
Related
I am building a small interface where I subclassed RViz which is a visualizer from ROS. According to the official documentation it is possible to re-use and re-implement some of the functions present in this tool. What I am trying to do is creating two different QPushButton that will chnage the view of the renderer implemented.
I have some problems with the SIGNAL ans SLOT for my two buttons, in fact as I click them, the view doesn't change.
Now RViz has a specific function called getNumViews() that allows the user to set the number of views. In my case I have two views only related to the two QPushButton I am implementing.
As I run the application program I receive the following error QObject::connect: No such slot MyViz::switchToView() and thought that all the passages to correctly set the SIGNALS and SLOT were correctly according to the official documentation. Also for completeness I am using C++11 and from researching more I found that the old version of the SIGNAL and SLOT, which is the one I am using is supposed to be still valid.
Below the code related to the SIGNAL and SLOT that I am running:
myviz.h
public Q_SLOTS:
void switchToView(QString view);
private:
rviz::ViewManager *view_man;
myviz.cpp
MyViz::MyViz(QWidget *parent) : QWidget(parent)
{
// operation in the constructor
QPushButton *topViewBtn = new QPushButton("Top View");
QPushButton *sideViewBtn = new QPushButton("Side View");
connect(topViewBtn, SIGNAL(clicked()), this, SLOT(switchToView(QString("Top View"))));
connect(sideViewBtn, SIGNAL(clicked()), this, SLOT(switchToView(QString("Side View"))));
}
here is where I set the 2 views possibilities related to the two QPushButtons
void MyViz::switchToView(QString view)
{
view_man = manager->getViewManager();
for(int i = 0; i<view_man->getNumViews(); i++)
{
if(view_man->getViewAt(i)->getName() == view)
view_man->setCurrentFrom(view_man->getViewAt(i));
return;
std::cout<<"Did not find view named %s"<<std::endl;
}
}
Thank you for pointing in the right direction for solving this issue.
You cannot pass arguments in the connect function using the old syntax. Also the number and type of arguments need to match, so you can only connect clicked to functions without arguments. If you want to use the old syntax, you need to define 2 slots
public Q_SLOTS:
void switchToTopView();
void switchToSideView();
which you can then connect via:
connect(topViewBtn, SIGNAL(clicked()), this, SLOT(switchToTopView()));
connect(sideViewBtn, SIGNAL(clicked()), this, SLOT(switchToSideView()));
edit:
The correct syntax for new connect method is:
connect( topViewBtn, &QPushButton::clicked, this, &MyViz::switchToTopView);
The advantage of this method is that you can also bind to lambdas, which indirectly lets you set parameters during connect, so you could write
connect( topViewBtn, &QPushButton::clicked, [this](){
switchToView( QString("Top View") );
});
I am trying to programmatically pass the content of a QLineEdit into rows of a QTableView using a QPushButton. I was wondering if there is anyone who can provide some guidance on how to do that.
Basically this is the initial situation:
and this is what I am trying to achieve using the QPushButton "Send To TableView" in a dynamical way, which mean that every time I change image and its related content shown inside the two QLineEdit I hit "Send To TableView" and the content is saved as shown below:
Every time I change image I repeat the process.
QSQLITE is the databse that is handling all the SQL for the QTableView. It is structured using this code from my previous question.
How to easily achieve that?
Thanks for shedding light on this issue.
I found out about this post that a very quick and easy answer is the following:
mainwindow.h
private slots:
void on_sendBtn_clicked();
void addData();
On the constructor put:
mainwindow.cpp
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
model = new QStandardItemModel();
ui->tableView->setModel(model);
}
Create the function that will be passed to the QPushButton
void MainWindow::on_sendBtn_clicked()
{
addData();
}
void MainWindow::addData()
{
QStandardItem *pathAItem = new QStandardItem(ui->pathLineEdit_A->text());
QStandardItem *pathBItem = new QStandardItem(ui->pathLineEdit_B->text());
QList<QStandardItem*> row;
row << pathAItem << pathBItem;
model->appendRow(row);
}
Hope this will be helpful should anyone needs
I am using a CellTable to display results of a query and I need these results to be shown as (html) links. I would like to react to a click on these links. So far, I had implemented it like this:
// ClickHandler on CellTable
cellTable.addCellPreviewHandler(new Handler<OperationalItemMultipleSearchRowData>() {
#Override
public void onCellPreview(CellPreviewEvent<OperationalItemMultipleSearchRowData> event) {
boolean isClick = "click".equals(event.getNativeEvent().getType());
if (isClick)
AdminUtils.EVENT_BUS.fireEvent(new SimpleSearchEvent(event.getValue().getName()));
}
});
The Problem is that this reacted to a Click on the whole row instead of the link. Due to architectural restrictions, the link itself is not a real html link, but a SafeHtml link that leads nowhere. I just needed the look&feel of a Link:
Column<OperationalItemMultipleSearchRowData, SafeHtml> nameColumn = new Column<OperationalItemMultipleSearchRowData, SafeHtml>(new SafeHtmlCell()) {
#Override
public SafeHtml getValue(final OperationalItemMultipleSearchRowData object) {
return new SafeHtml() {
#Override
public String asString() {
return "" + object.getName() + "";
}
};
}
};
How can I react to a click on this link only ? (instead of the whoel row)
Is there a more elegant way to implement this ?
Cheers
As with any other use of event delegation, the basic idea is to find walk up the hierarchy starting from the target of the event up until you find the link element you're looking for, or some other element that signals the search is over and the click was targetted outside the link (e.g. you reached the cell, the row or the table).
That being said, I think you should merge your behavior inside a specific Cell implementation rather than using a CellPreviewHandler (copy/paste the ActionCell or TextButtonCell as a starting point).
As a side note, I also believe you should not use a link when you're not actually linking anywhere, or try to provide a target for the link if the behavior is the one of a link (that way, right-clicking, middle-clicking or ctrl-clicking will Just Workâ˘). If you want the look of a link (without the "feel"), then just use an ActionCell or TextButtonCell and style it accordingly.
I using the wxFormbuilder to mimic a QT GUI design, but I always can not success to make a ideal result.
The question is related the alignment/layout. Can anyone give me a hand?
Because I can not attach files here, so I uploaded the wxFormbuilder project file and a qt-gui screenspot .png file to the links below.
If anyone has time, plz give me a guide.
The wxFrombuild project file and the qt_gui .png files are here. http://www.2shared.com/file/62BJYq2l/help_dlg.html http://www.2shared.com/photo/uWl3XmRl/qt_GUI.html
Your design is fairly complicated. I don't use wxFormbuilder, I like to set up my form manually, by "hard coding" the layout.
So before I explain how I would do it, here's a few advice:
I would put the ok/cancel/help bar somewhere else (in a separate wxPanel, and put them together in the dialog at the end)
I would move the test connect button on the ok/cancel/help bar.
The test connect button is in an awful place at the moment in term of setting the layout
(optionally) I would split the form between name/host/database and username/password since they represent some sub unit you can reuse somewhere else
Now here is how I would build the form. I let you implement the getValue and setValue.
Also you'll need to do something similar for the tool bar (using a wxBoxSizer) and put them together (using a wxBoxSizer again).
Also if you may want to use a wxStaticBox
class ConnectionEditor
: wxPanel
{
public:
ConnectionEditor(wxWindow* parent);
//
void getValue(ConnectionSettings&);
void setValue(ConnectionSettings const&);
private:
wxTextCtrl* name_;
wxTextCtrl* host_;
wxTextCtrl* database_;
wxTextCtrl* username_;
wxTextCtrl* password_;
wxCheckBox* save_password_;
};
wxTextCtrl* CreateTextControl(wxWindow* parent)
{
return new wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(100, 20));
}
wxTextCtrl* CreateStaticText(wxWindow* parent, std::string const& text)
{
return new wxStaticText(parent, wxID_ANY, text.c_str());
}
ConnectionEditor::ConnectionEditor(wxWindow* parent)
: wxPanel(parent, wxID_ANY)
{
this->name_ = CreateTextControl(this);
this->host_ = CreateTextControl(this);
this->database_ = CreateTextControl(this);
this->username_ = CreateTextControl(this);
this->password_ = CreateTextControl(this);
this->save_password_ = new wxCheckBox(this, wxID_ANY, "on");
//
wxFlexGridSizer* sizer = new wxFlexGridSizer(6, 2, 5, ,5); // 6 rows, 2 cols, 5 spacing in between
//
sizer->Add(CreateStaticText(this, "Name"));
sizer->Add(this->name_);
sizer->Add(CreateStaticText(this, "Host"));
sizer->Add(this->host_);
sizer->Add(CreateStaticText(this, "Database"));
sizer->Add(this->database_);
sizer->Add(CreateStaticText(this, "Username"));
sizer->Add(this->username_);
sizer->Add(CreateStaticText(this, "Password"));
sizer->Add(this->password_);
sizer->Add(CreateStaticText(this, "Save Password"));
sizer->Add(this->save_password_);
//
this->SetSizerAndFit(sizer);
}
I have an array of CheckboxField[] elements that I need to dynamically initialize. My sample code is -
class abc extends MainScreen implements FieldChangeListener {
CheckboxField[] boxField;
abc() {
.
.
.
boxField = new CheckboxField[length];
VerticalFieldManager vfm = new VerticalFieldManager();
for(int i=0; i<length; i++) {
boxField[i] = new CheckboxField(var[i], false);
boxField[i].setChangeListener(this);
vfm.add(boxField[i]);
}
add(vfm);
}
public void fieldChanged(Field field, int context) {
// The idea is to disable all the other checkboxes when one
// is clicked.
boxField[0].setChecked(false); // Gives stackoverflow error on JVM.
}
}
Any help?
Edit: The problem only seems to be with .setChecked(boolean)
I've tried chkboxField[0].setFont(), chkboxField.getChecked(), both of them seem to work.
So, what's apparently happening is boxField[i].setChecked(false) calls the FieldChangeListener again, and this loops infinitely till the stack blows.
I was told to use
if(context != FieldChangeListener.PROGRAMMATIC) {
boxField[i].setChecked(false);
}
Based on your comment in the FieldChanged method, it sounds like you have mutually exclusive checkboxes (that is, you have a group of checkboxes and when any one is checked, all the rest should be unchecked).
If so, you may want to consider using the RadioButtonField instead. You can stick your radio buttons into a RadioButtonGroup and then the BlackBerry will take care of unchecking for you.