Qt: QObject::connect: No such slot - c++11

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") );
});

Related

How to show proper QStackedWidget page after QListWidget selection

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. :)

How to programmatically pass QLineEdit content into QTableView rows using QPushButton

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

Determining if all items in a collection meet established critera

This seems to be a problem that comes up a lot. I've been coming up with the same solution nearly every time but was curious if people have a better method of accomplishing this.
I have one class that is a list of instances of another class. The state of the parent class is dependent upon state of ALL the children
As an example. Say I have the following classes
class Box
{
int _objectId= <insert_unique_id>;
int _itemCount = 0;
public void AddItem()
{
_itemCount = Max(_itemCount + 1, 5);
}
public int GetId()
{
return _objectId;
}
public bool IsFull()
{
return _itemCount == 5
}
}
class BiggerBox
{
Map<int, Box> _boxes;
public void AddToBox(int id)
{
_boxes[id].AddItem();
}
public bool IsFull()
{
foreach(var box in _boxes.Values)
if(!box.IsFull())
return false;
return true;
}
}
All additions to a "Box" are done via the BiggerBox.AddToBox call. What I would like to do is be able to determine box.IsFull() without iterating over every single item every time we add an element.
Typically i accomplish this by keeping a SET or a separate collection of what items are full.
Curious, has anyone come up to an ingenious solution to this or is the simple answer that there is no other way?
There are two things you need to do in order to accomplish what you want:
Be able to control every entrypoint to your collection
React to changes to the objects in the collection
For instance, if the objects in the collection are mutable (meaning, they can change after being added to your collection) you need your main object to react to that change.
As you say, you could create a separate set of the objects that are full, but if the objects can change afterwards, when they change you either need to take them out of that set, or add them to it.
This means that in order for you to optimize this, you need some way to observe the changes to the underlying objects, for instance if they implement INotifyPropertyChanged or similar.
If the objects cannot change after being added to your main object, or you don't really care if they do, you just need to control every entrypoint, meaning that you basically need to add the necessary checks to your AddItem method.
For your particular types I would implement an event on the Box class so that when it is full, it fires the event. Your BiggerBox class would then hook into this event in order to observe when an underlying box becomes full.
You can upkeep the number of complete (or non-complete) boxes in BiggerBox class, and update it in all the functions.
E.g., in AddToBox it could be:
bool wasFull = _boxes[id].IsFull;
_boxes[id].AddItem();
if (!wasFull && _boxes[id].IsFull) // After this update box has become full.
completeBoxes += 1;
It is also possible to implement this upkeep procedure in other hypothetical functions (like RemoveFromBox, AddBox, RemoveBox, etc.)

Tools/Guide to Creating an Image Looper in GWT

I'm setting out to create a weather model display tool (web application), and from what I've seen, I'm really liking the idea of using Google Web Tools, and especially the SmartGWT toolkit. My one biggest sticking point at this point is finding some way to create a sort of image "looper" (displaying all images in a particular "set" one after another, not unlike a slide show). For reference, I need functionality (at least on a basic level) similar to this: http://rapidrefresh.noaa.gov/hrrrconus/jsloop.cgi?dsKeys=hrrr:&runTime=2012053007&plotName=cref_sfc&fcstInc=60&numFcsts=16&model=hrrr&ptitle=HRRR%20Model%20Fields%20-%20Experimental&maxFcstLen=15&fcstStrLen=-1&resizePlot=1&domain=full&wjet=1 (though it certainly need not be exactly like that).
Does anyone know of (ideally) some sort of GWT module that can do image looping? Or if not, does it sound like something an intermediate programmer could figure out without too much trouble (I'm willing to accept a challenge), even if I've never explicitly used GWT before? I'm sure I could whip together something that pulls each image in as it goes through a loop, but prefetching them would be even more ideal.
Please comment if you need clarification on anything!
As far as I'm aware there's not a pre-fab solution to do this, although maybe SmartGWT has something I don't know about. In any case, it won't be too hard to roll your own. Here's some code to get you started:
public class ImageLooper extends Composite {
// List of images that we will loop through
private final String[] imageUrls;
// Index of the image currently being displayed
private int currentImage = 0;
// The image element that will be displayed to the user
private final Image image = new Image();
// The Timer provides a means to execute arbitrary
// code after a delay or at regular intervals
private final Timer imageUpdateTimer = new Timer() {
public void run() {
currentImage = (currentImage + 1) % images.length;
image.setUrl(imageUrls[currentImage]);
}
}
// Constructor. I'll leave it to you how you're going to
// build your list of image urls.
public ImageLooper(String[] imageUrls) {
this.imageUrls = imageUrls;
// Prefetching the list of images.
for (String url : imageUrls)
Image.prefetch(url);
// Start by displaying the first image.
image.setUrl(imageUrls[0]);
// Initialize this Composite on the image. That means
// you can attach this ImageLooper to the page like you
// would any other Widget and it will show up as the
// image.
initWidget(image);
}
// Call this method to start the animation
public void playAnimation() {
// Update the image every two seconds
imageUpdateTimer.scheduleRepeating(2000);
}
// Call this method to stop the animation
public void stopAnimation() {
imageUpdateTimer.cancel();
}
}
One annoying thing with this implementation is that you have no way of knowing when your list of images has finished loading; Image.prefetch doesn't have a callback to help you here.

ViewModels and IsolatedStorageSettings

Im working on a MVVM Windows phone app that displays weather info.
When the app loads up it opens MainPage.xaml. It makes a call the the service to get weather info and binds that data to the UI. Both Fahrenheit and Celcius info are returned but only one is displayed.
On the setting page, the user can select to view the temp in either Fahrenheit or Celcius.
The user can change this setting at any time and its stored in IsolatedStorageSettings.
The issue Im having is this:
when the user navigates to the Settings page and changes their preference for either Fahrenheit or Celcius, this change is not reflected on the main page.
This issue started me thinking about this in a broader context. I can see this being an issue in ANY MVVM app where the display depends on some setting in IsolatedStorage. Any time any setting in the IsoStore is updated, how does the ViewModels know this? When I navigate back in the NavigationStack from the settings page back to MainPage how can I force a rebind of the page?
The data in my model hasnt changed, only the data that I want to display has changed.
Am I missing something simple here?
Thanks in advance.
Alex
Probably you have code like this:
public double DisplayTemperature
{
get { return (IsCelsium) ? Celsium : Fahrenheit; }
}
And IsCelsium is:
public double IsCelsium
{
get { return (bool)settings["IsCelsium"]; }
set { settings["IsCelsium"] = value; }
}
So you need to add NotifyPropertyChanged event to notify UI to get new values from DisplayTemperature property:
public double IsCelsium
{
get { return (bool)settings["IsCelsium"]; }
set
{
settings["IsCelsium"] = value;
NotifyPropertyChanged("DisplayTemperature");
}
}
Take a look at Caliburn Micro. You could implement something similar or use CM itself. When using CM I don't even think about this stuff, CM makes it so simple.
When your ViewModel inherits from Screen there are life-cycle events that fire that you can override. For example, OnInitialize fires the very first time the ViewModel is Activated and OnActivate fires every time the VM is activated. There's also OnViewAttached and OnViewLoaded.
These methods are the perfect place to put logic to populate or re-populate data.
CM also has some special built in features for allowing one to easily tombstone a single property or an entire object graph into Iso or phone state.
ok, so Ive come up with a solution. Before I get to it, let me provide some background. The app that Im working on uses both MVVM Light and WP7Contrib. That being the case, I am using Funq for DI and the MVVMLight Toolkit. After I posted my initial question, I gave the question a bit more thought. I remembered a video that I watched a while back from MIX2011 called Deep Dive MVVM with Laurent Bugnion
http://channel9.msdn.com/Events/MIX/MIX11/OPN03
In it, he talks about just this problem (view models not living at the same time) on Windows Phone. The part in question starts around the 19 minute mark.
Anyway, after I remembered that and realized that the ViewModel locator is exposed in App.xaml, this became a trivial problem to solve. When the user changes the Fahrenheit/Celcius option on the setting page, I simply get a reference to the MainViewModel via the ViewModelLocator and reset the collection that is bound to the UI thus causing the bindings to update.
public bool AddOrUpdateValue(string Key, Object value)
{
bool valueChanged = false;
// If the key exists
if (settings.Contains(Key))
{
// If the value has changed
if (settings[Key] != value)
{
// Store the new value
settings[Key] = value;
valueChanged = true;
}
}
// Otherwise create the key.
else
{
settings.Add(Key, value);
valueChanged = true;
}
return valueChanged;
}
public bool ImperialSetting
{
get
{
return GetValueOrDefault<bool>(ImperialSettingKeyName, ImperialSettingDefault);
}
set
{
if (AddOrUpdateValue(ImperialSettingKeyName, value))
{
Save();
RaisePropertyChanged("ImperialSettingText");
var vml = new ViewModelLocator();
vml.MainViewModel.Cities = (App.Current as App).Cities;
}
}
}
It was a mistake on my part not to realize that I could get access to the viewModel via the ViewModelLocator. Hopefully this post saves someone else the time I burned on this issue.

Resources