i am creating a software using C++ and QT,and i have two widget one of type QRadioButon and one QTabWidget. My need is that i want to send signal from a radio button and i want that whenever the button is checked the content of tab get changed.
Can anyone suggest how to do that? I tried creating a slot of my widget class and in that slot i called the constructor of tab class but the problem is the construtor is not getting called.
here is the code i am using..
#include <QtGui>
#include "v_lab.h"
v_lab::v_lab(QWidget *parent)
: QDialog(parent)
{
setWindowTitle("Virtual Lab");
maingroup=new QGroupBox(this);
maingroup->setTitle("Algorithms");
maingroup->setMinimumWidth(200);
maingroup->setMaximumWidth(240);
maingroup->setFlat(false);
p=new QPalette;
p->setColor(QPalette::Background,QColor(233,212,102));
setPalette(*p);
box=new QGroupBox(maingroup);
box->setFlat(false);
box->setTitle("Searching Algorithm");
linear_search=new QRadioButton("Linear Search",box);
linear_search->setChecked(1);
binary_search=new QRadioButton("Binary Search",box);
box1=new QGroupBox(maingroup);
box1->setFlat(false);
box1->setTitle("Sorting Algorithms");
bubble_sort=new QRadioButton("Bubble Sort",box1);
selection_sort=new QRadioButton("Selection Sort",box1);
box2=new QGroupBox(maingroup);
box2->setFlat(false);
box2->setTitle("Tree Algorithms");
infix_traversal=new QRadioButton("Infix Traversal",box2);
prefix_traversal=new QRadioButton("Prefix Traversal",box2);
postfix_traversal=new QRadioButton("Postfix Traversal",box2);
box3=new QGroupBox(maingroup);
box3->setFlat(false);
box3->setTitle("Graph Algorithms");
bfs=new QRadioButton("BFS",box3);
dfs=new QRadioButton("DFS",box3);
shortest_path=new QRadioButton("Shortest Path",box3);
QString string1="go to hell";
tab=new QTabWidget;
tab->addTab(new algorithm(string1),"Algorithm");
// tab->addTab(new psudo_code(),"Pseduo-Code");
tab->setMinimumWidth(250);
tab->setMaximumWidth(400);
//Layout
mainlayout=new QHBoxLayout(this);
mainlayout->addWidget(maingroup);
mainlayout->addWidget(tab);
mainlayout->addStretch();
main_left_pane_layout=new QVBoxLayout(maingroup);
main_left_pane_layout->addWidget(box);
main_left_pane_layout->addWidget(box1);
main_left_pane_layout->addWidget(box2);
main_left_pane_layout->addWidget(box3);
left_pane_box=new QVBoxLayout(box);
left_pane_box->addWidget(linear_search);
left_pane_box->addWidget(binary_search);
left_pane_box1=new QVBoxLayout(box1);
left_pane_box1->addWidget(bubble_sort);
left_pane_box1->addWidget(selection_sort);
left_pane_box2=new QVBoxLayout(box2);
left_pane_box2->addWidget(infix_traversal);
left_pane_box2->addWidget(prefix_traversal);
left_pane_box2->addWidget(postfix_traversal);
left_pane_box3=new QVBoxLayout(box3);
left_pane_box3->addWidget(bfs);
left_pane_box3->addWidget(dfs);
left_pane_box3->addWidget(shortest_path);
connect(binary_search,SIGNAL(clicked()),this,SLOT(peeyush()));
}
algorithm::algorithm(const QString &string,QWidget *parent)
: QWidget(parent)
{
label=new QLabel(string);
main_layout=new QVBoxLayout;
main_layout->addWidget(label);
main_layout->addStretch();
setLayout(main_layout);
}
/*
psudo_code::psudo_code(QWidget *parent)
: QWidget(parent)
{
label1=new QLabel("Hello Peeyush Chandel");
main_layout1=new QVBoxLayout;
main_layout1->addWidget(label1);
main_layout1->addStretch();
setLayout(main_layout1);
}
*/
void v_lab::peeyush()
{
QString string1="new string";
algorithm obj(string1);
//exit(1);
}
In the header definition file of your v_lab class you should have something like this:
// Includes here.
class v_lab: public QDialog
{
Q_OBJECT // VERY important!
public:
// Other things here.
private slots: // VERY important. You can use public slots too.
void peeyush();
}
And you cannot connect a signal to a constructor.
Related
this is the first time i write in this site, I'm trying approach me at Qt-creator but I've a problem:
I want to delete the text of the label when the user click a button, i've tried some solution but without success
this is the code:
struct finestra{
float costo;
int altezza;
int larghezza;
QString text;
QString costoStr;
};
float Totale=0;
finestra vet[21];
int i=1;
//SOME CODE
Totale+=vet[i].costo;
vet[i].costoStr = QString::number(vet[i].costo);
vet[i].text = vet[i-1].text + "Finestra ad un anta bianca <br>" + "€" + vet[i].costoStr +"<br>";
ui->TotaleFinestre->setText(QString(vet[i].text));
i++;
I've tried with this function:
void preventivi::on_pushButton_clicked()
{
ui->TotaleFinestre->clear();
}
if someone know how to do please answer,
thanks to all and sorry for my bad english.
Maybe you should try
void preventivi::on_pushButton_clicked()
{
ui->TotaleFinestre->setText("");
}
As QLabel define the slot void QLabel::clear(), you can also just connect this slot with the clicked() signal that will be emitted after a click on your pushButton, using the QObject::connect method :
QObject::connect(pointer_to_your_pushButton, SIGNAL(clicked()), pointer_to_your_label, SLOT(clear()));
EDIT : Here is a small example
The UI is a QWidget that has a QLabel and a QPushButton. I did that with Qt Designer but it doesn't matter here.
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QObject::connect(ui->pushButton, SIGNAL(clicked()), ui->label, SLOT(clear()));
}
Widget::~Widget()
{
delete ui;
}
You can even do that using "Edit Signals/Slots" inside Qt Designer and make the signal/slot connection between your widgets. ( you won't need to manually call the previous QObject::connect, as it will be done automatically inside the Ui_Widget class, generated by the uic)
Or you can do all without Qt Designer, it's up to you.
Hope this helps.
I'm learning the signals/slots in Qt and I have found a problem. I need to create my own slot that is called when items on QGraphicsScene (in QGraphicsView) are moved or selected.
I'm starting with a simple app that has one widget and on it is graphicsView and label. I've created a slot in my window and connected it to QGraphicsScene's signal, but it is not being used. Where is my mistake?
Here is the code:
//MainWindow.h
//as generated by QtCreator, just added one slot to it
...omitted for brevity...
public slots:
void selectedItemChanged(QGraphicsItem * newItem, QgraphicsItem * oldItem);
..omitted for brevity...
//------------------------------------------------------------------
//MainWindow.cpp
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
QGraphicsScene * scene = new QGraphicsScene();
scene->setBackgroundBrush (QBrush(Qt::gray));
ui->graphicsView->setScene (scene);
for(int x = 10; x < 250; x+=20)
{
QGraphicsEllipseItem * item = scene->addEllipse (x,x,5,5,QPen(Qt::darkGreen),QBrush(Qt::darkGreen));
item->setFlag (QGraphicsItem::ItemIsFocusable,true);
}
QObject::connect (scene,SIGNAL(focusItemChanged),this,SLOT(selectedItemChanged));
}
void MainWindow::selectedItemChanged (QGraphicsItem *newItem, QGraphicsItem *oldItem)
{
qDebug()<<"called";
if(newItem == 0)
{
ui->label->setText ("Není vybrán bod");
}
else
{
ui->label->setText (QString::number (newItem->scenePos ().x ()) + "," + QString::number (newItem->scenePos ().y ()));
}
}
Now, when I run the probram it rins ok, but I cannot set Focus on the circles(ellipses) drawn on the scene and the slot is not used. I tried setting IsSelectable flag, but it does not help. Is there any other preferred way to get this done or solution to my problem?
You're not linking against the signal's right signature, according to the documentation:
void QGraphicsScene::focusItemChanged( QGraphicsItem * newFocus, QGraphicsItem * oldFocus,
Qt::FocusReason reason)
and also notice that you can check the connection's success/failure status via the bool return type of the QObject::connect method
So, in the end i found the answer to my own question. It was a mistake on my side.
in the connect() i used the slots without parenthesis/parameters. It should have looked like:
QObject::connect (scene,
SIGNAL(focusItemChanged(QGraphicsItem*,QGraphicsItem*,Qt::FocusReason)),
this,
SLOT(selectedItemChanged(QGraphicsItem*,QGraphicsItem*)));
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.");
}
I am trying to create a program that waits for the user to input something into a line edit widget, and when they hit enter, I want to compare the value to some predefined one (for example "1"). The problem I seem to be having is that I cannot find a way to make this work with the QStateMachine. At the moment, it will wait for the user to press enter and it just switches over to the next state, but I want it to only go to the next state if the input is "1". Here is the code I am using and thank you for any help that you can offer.
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
connect(ui->lineEdit, SIGNAL(editingFinished()), this, SLOT(someSlot()));
setupStateMachine();
}
...
void MainWindow::setupStateMachine()
{
QStateMachine *machine = new QStateMachine(this);
QState *s1 = new QState();
QState *s2 = new QState();
QState *s3 = new QState();
s1->assignProperty(ui->label, "text", readFile("intro.txt"));
s2->assignProperty(ui->label, "text", "In state s2");
s3->assignProperty(ui->label, "text", "In state s3");
s1->addTransition(this, SIGNAL(editing()), s2);
s2->addTransition(this->ui->pushButton, SIGNAL(clicked()), s3);
s3->addTransition(this->ui->pushButton, SIGNAL(clicked()), s1);
machine->addState(s1);
machine->addState(s2);
machine->addState(s3);
machine->setInitialState(s1);
machine->start();
qDebug() << "State Machine Created";
}
...
void MainWindow::someSlot()
{
if(ui->lineEdit->text() == "1")
{
emit editing();
}
}
In the header file:
{
...
signals:
void editing();
...
private slots:
void someSlot();
...
};
PS: I realize that the signal does not do what I want, but I can't figure out which signal to use.
Perhaps you can connect editingFinished to your own slot. In that slot, check if the input is "1". if so, emit a new signal you pass into addTransition instead of editingFinished
To add a signal to a class, change the class like this (make sure there is a Q_OBJECT declared at the very top of the class):
signals:
void mySignalName();
Signals are guaranteed protected. You don't write the body of the function. That's what MOC does. So, when you want to call the signal in your class, just call:
emit mySignalName();
emit is just for code documentation. It's #defined to nothing. MOC will generate the body of mySignalName and boil down to calls to the slots you connect it to using QObject::connect.
To add a new slot to your class, add this:
private slots:
void mySlotName();
Note that you will have to write the body of a slot.
void MainWindow::mySlotName()
{
if(myLineEdit->text() == "1")
emit mySignalName();
}
I have a question about Qt. I am wondering how it is I should delete all the pointers I create. For example:
.h file
#ifndef MAINCALENDAR_H
#define MAINCALENDAR_H
#include<QWidget>
#include <QMap>
#include <QComboBox>
#include <QCalendarWidget>
#include <QRadioButton>
#include <QString>
#include <QtGui>
#include "selector.h"
#include <QInputDialog>
class mainCalendar : public QWidget
{
Q_OBJECT
public:
mainCalendar(QWidget * parent = 0);
~mainCalendar();
void showAppointments();
public slots:
void showLCFunc() {select->getTod()->getIntf()->getListClass().orderListChronologic(); printer * test = new printer; test->setList(TodFace->getList()); test->show();}
void showLPFunc() {select->getTod()->getIntf()->getListClass().orderListByPriority(); printer * test = new printer; test->setList(TodFace->getList()); test->show();}
void loadFile() {QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"),"", tr("M-Calendar Files (*.mca)"));}
void saveFile() {QString fileName = QFileDialog::getSaveFileName(this, tr("Save File"),"", tr("M-Calendar Files (*.mca)"));qDebug() << fileName << endl;}
void intshow();
void updater() {if (!Interface->isHidden()) { app->setList(Interface->getList()); app->Beta_update(1,calendar->selectedDate()); }
else if (!TodFace->isHidden()) {tod->setList(TodFace->getList()); tod->Beta_update(1,calendar->selectedDate());} }
private:
QPushButton *showLC;
QPushButton *showLP;
QPushButton *searchButton;
QPushButton *updateButton;
QPushButton *saveButton;
QPushButton *loadButton;
QLabel *instructions;
QPushButton *backButton;
QPushButton *taskButton;
interface * Interface;
todFace * TodFace;
showTod * tod;
showApp * app;
QCalendarWidget *calendar;
QGridLayout *mainLayout;
Selector * select;
};
#endif // MAINCALENDAR_H
.cpp file:
#include "maincalendar.h"
mainCalendar::mainCalendar(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout * footButtons = new QHBoxLayout;
showLC = new QPushButton(tr("'to-do' (chrono)"));
showLP = new QPushButton(tr("'to-do' (priority)"));
searchButton = new QPushButton(tr("&Search"));
saveButton = new QPushButton(tr("&Save calendar"));
loadButton = new QPushButton(tr("&Load Calendar"));
updateButton = new QPushButton(tr("Update"));
footButtons->addWidget(searchButton);
footButtons->addWidget(saveButton);
footButtons->addWidget(loadButton);
footButtons->addWidget(showLC);
footButtons->addWidget(showLP);
instructions = new QLabel(tr("To view or add data, double-click date in calendar"));
calendar = new QCalendarWidget;
calendar->setGridVisible(true);
calendar->setMinimumDate(QDate(2012, 1, 1));
calendar->setMaximumDate(QDate(2016,12,31));
backButton = new QPushButton(tr("&Back to calendar"));
select = new Selector(0,calendar,instructions,backButton, updateButton);
tod = select->getTod();
TodFace = tod->getIntf();
TodFace->hide();
TodFace->setCalendar(calendar);
tod->hide();
app = select->getApp();
Interface = app->getIntf();
Interface->hide();
Interface->setCalendar(calendar);
app->hide();
backButton->hide();
updateButton->hide();
connect(showLC,SIGNAL(clicked()),this,SLOT(showLCFunc()));
connect(showLP,SIGNAL(clicked()),this,SLOT(showLPFunc()));
connect(updateButton, SIGNAL(clicked()), this, SLOT(updater()));
connect(backButton, SIGNAL(clicked()), this, SLOT(intshow()));
connect(loadButton,SIGNAL(clicked()),this,SLOT(loadFile()));
connect(saveButton,SIGNAL(clicked()),this,SLOT(saveFile()));
connect(calendar, SIGNAL(activated(QDate)), this, SLOT(intshow()));
mainLayout = new QGridLayout;
this->setMinimumHeight(800);
this->setMinimumWidth(1000);
mainLayout->setColumnMinimumWidth(0,500);
mainLayout->addWidget(calendar,0,0);
mainLayout->addWidget(app,1,0);
mainLayout->addWidget(Interface,1,2);
mainLayout->addWidget(tod,1,0);
mainLayout->addWidget(TodFace,1,2);
mainLayout->addWidget(backButton,0,0,Qt::AlignTop);
mainLayout->addLayout(footButtons,2,0,Qt::AlignLeading);
mainLayout->addWidget(instructions,2,0,Qt::AlignTrailing);
mainLayout->addWidget(updateButton,2,2,Qt::AlignRight);
setLayout(mainLayout);
setWindowTitle(tr("M-Calendar"));
}
mainCalendar::~mainCalendar()
{
}
void mainCalendar::intshow()
{
if (Interface->isHidden()&&TodFace->isHidden())
{
select->setDate(calendar->selectedDate());
select->show();
Interface->setdate(calendar->selectedDate());
TodFace->setdate(calendar->selectedDate());
} else
{
backButton->hide();
updateButton->hide();
Interface->hide();
app->close();
TodFace->hide();
tod->close();
calendar->show();
instructions->show();
}
}
I am stuck here. Am I supposed to do to delete all the pointers (QPushbutton, etc) and subclasses so no memory leaks occur?
Short answer: No, you don't have to explicitly delete them.
In Qt, the QObjects are organized in object trees. The parent-child relationships of the various widgets also implies that the parent takes ownership of the child widgets.
As a result you do not have to explicitly delete them when your application finishes. Each parent will take care of the cleanup of its own children. Only when you create a (pointer to) a widget/object which has no parent, you will need to explicitly delete it.
via addWidget you create a parent-child-relationship between these to widgets.
Any parentless widget has to be destroyed manually, which in turn free its children recursivly.
As long as your widget has a parent, and that is either freed manually or child to another Widget, no manual free is required.
Same accounts for QObject derived classes.