Change QStackedLayout Index with QPushButton not QComboBox - c++

I do this in Qt Creator. I want to change my QStackedLayout with only QPushButton, not QComboBox. Is this possible? Anybody has implemented this? I got many example from Qt Documentation but all examples use QComboBox (now QPushButton like I need). This is my code:
#mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
Dialog::Dialog()
{
QVBoxLayout *mainlayout = new QVBoxLayout;
QVBoxLayout *layouta = new QVBoxLayout;
QVBoxLayout *layoutb = new QVBoxLayout;
QPushButton *tombola = new QPushButton("A");
QPushButton *tombolb = new QPushButton("B");
QPushButton *tombolc = new QPushButton("C");
QFrame *framea = new QFrame;
QFrame *frameb = new QFrame;
QStackedLayout *stackia = new QStackedLayout;
layouta->addWidget(tombola);
layoutb->addWidget(tombolb);
framea->setLayout(layouta);
frameb->setLayout(layoutb);
framea->setMinimumSize(88,88);
frameb->setMinimumSize(88,88);
//building frame
framea->setFrameShape(QFrame::StyledPanel);
framea->setFrameShadow(QFrame::Raised);
frameb->setFrameShape(QFrame::StyledPanel);
frameb->setFrameShadow(QFrame::Raised);
//get c button smaller
tombolc->setMaximumWidth(33);
stackia->addWidget(framea);
stackia->addWidget(frameb);
stackia->addWidget(tombolc);
mainlayout->addLayout(stackia);
QPushButton *tombold = new QPushButton("D");
mainlayout->addWidget(tombold);
setLayout(mainlayout);
connect(tombold, SIGNAL(clicked()), stackia, SLOT(setCurrentIndex(1))); //CONNECTOR
}
RESULT
Qt Creator says:
Object::connect: No such slot QStackedLayout::setCurrentIndex(1)
What is my mistake?
At second chance after searching and asking for 4 days, I have changed my connect() and function code into:
CONNECTOR:
connect(tombold, SIGNAL(clicked()), stackia, SLOT(change_stack()));
FUNCTION:
void Dialog::change_stack()
{
stackia->setCurrentIndex(1);
}
RESULT
But Qt Creator says:
Object::connect: No such slot QStackedLayout::change_stack()
and immediately the window closed.
At my sight, my code has error. But I don't know what error so I can't change QStackLayout content/page into another page. What is my mistake? I believe this is actually quite simple but I just don't know where is the error.
Any suggestion?

You should add change_stack function to your Dialog class and connect to it like this:
class Dialog : public QWidget
{
...
private slots:
void change_stack();
private:
QStackedLayout *stackia;
}
Dialog::Dialog
{
...
connect(tombold, SIGNAL(clicked()), this, SLOT(change_stack()));
...
}
void Dialog::change_stack()
{
stackia->setCurrentIndex(1);
}

Concerning
connect(tombold, SIGNAL(clicked()), stackia, SLOT(setCurrentIndex(1)));
A slot can only have as many parameters or less parameters than a signal.
E.g. you can do
connect( sender , SIGNAL( somethingHappened( const QString& ) ),
receiver, SLOT ( doSomething ( const QString& ) ) );
and you can do
// connect signal and ignore the parameter
connect( sender , SIGNAL( somethingHappened( const QString& ) ),
receiver, SLOT ( doSomethingElse ( ) ) );
but you cannot do
// this will not work
connect( sender , SIGNAL( somethingElseHappened( ) ),
receiver, SLOT ( doSomething ( const QString& ) ) );
What you probably want is something like this:
Dialog::Dialog
{
...
// This must be a member variable
_stackia = new QStackedLayout();
tombola->setProperty( "tabpage", 1 );
tombolb->setProperty( "tabpage", 2 );
tombolc->setProperty( "tabpage", 3 );
connect( tombola, SIGNAL( clicked () ),
this , SLOT ( tombol_clicked() ) );
connect( tombolb, SIGNAL( clicked () ),
this , SLOT ( tombol_clicked() ) );
connect( tombolc, SIGNAL( clicked () ),
this , SLOT ( tombol_clicked() ) );
}
// This must be defined as slot in the header
void Dialog::tombol_clicked()
{
int index = sender()->property( "tabpage" ).toInt();
_stackia->setCurrentIndex( index );
}

Related

Replacing deprecated QtSignalMapper class to forward Signals in Qt5

I have this code which makes a mdi window written for Qt 4:
class MdiWindow : public QMainWindow
{
Q_OBJECT
public:
MdiWindow( QWidget *parent = nullptr)
...
private:
QWorkspace* workspace
QSignalMapper* mapper
}
MdiWindow::MdiWindow( QWidget *parent ) : QMainWindow( parent )
{
...
workspace = new QWorkspace;
setCentralWidget( workspace );
connect( workspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(enableActions()));
mapper = new QSignalMapper( this );
connect( mapper, SIGNAL(mapped(QWidget*)), workspace, SLOT(setActiveWindow(QWidget*)) );
....
}
According to the QT documentation QWorkspace should be replaced with QMdiArea.
I did that and wrote the first connect like this:
connect(workspace, &QMdiArea::subWindowActivated,
this, &MdiWindow::enableActions);
But what about QSignalMapper also that is also deprecated.
So how can I update this line:
mapper = new QSignalMapper( this );
connect( mapper, SIGNAL(mapped(QWidget*)), workspace, SLOT(setActiveWindow(QWidget*)) );
I read QSignalMapper can be replaced with lamdas but how in this case?
If i understand right mapper forwards all the signals from this to the active window of workspace
Previously you used QSignalMapper::setMapping() to make sure that you'd be sent data you need when the SLOT() was called. Now you can just encapsulate this logic inside a lamba, so if you did (like in Qt example):
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, texts[i]);
}
connect(signalMapper, SIGNAL(mapped(const QString &)),
this, SIGNAL(clicked(const QString &)));
you can now do (somewhat):
for (int i = 0; i < texts.size(); ++i) {
QPushButton *button = new QPushButton(texts[i]);
connect(button, &QPushButton::clicked, [=]() {
emit clicked(texts[i]);
});
}
If the setMapping() is not being used, then it probably could have been connected directly to a SLOT() already.

How to add clear option t qplaintextedit?

I have a qplaintextedit that is loaded dynamically with text contents, with QString.
I want to add an option to the menu that appears when we right click on the qplaintextedit. How can I do it programmatically so that I am able to add my own menu item to the default menu item? Any ideas would be appreciated.
You can sublcass QPlainTextEdit and reimplement the method contextMenuEvent(QContextMenuEvent *event). Alternatively you can add an event filter to a QPlainTextEdit and catch the QContextMenuEvent.
In your implementation, you can call QMenu *QPlainTextEdit::createStandardContextMenu(const QPoint &position) to create the default menu of the text edit and than add your custom items to it.
Example (subclass):
void MyTextEdit::contextMenuEvent(QContextMenuEvent *event)
{
QMenu* menu = createStandardContextMenu(event->pos());
QAction* clearAction = menu->addAction("Clear");
QAction* choosedAction = menu->exec(event->globalPos());
//...
delete menu;
}
See:
Event handlers
Event filters
QPlainTextEdit::contextMenuEvent
QPlainTextEdit::createStandardContextMenu
You have to reimplement the function : void QPlainTextEdit::contextMenuEvent(QContextMenuEvent *event)
More details in the doc here : http://doc.qt.io/qt-5/qplaintextedit.html#contextMenuEvent
It is not necessary to subclass QPlainTextEdit, nor to use an event filter. You can do it all in the main widget of your application. The following worked for me using Qt versions 4.7.4 and 4.8.5.
In the Designer:
You add a QPlainTextEdit widget whose name is "textbox".
In MainWindow.h:
// Auto generated from MainWindow.ui
#include "ui_MainWindow.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
/// The auto generated user interface.
Ui::MainWindowClass ui;
...
}
In MainWindow.cpp:
MainWindow::MainWindow( QWidget * pParent, Qt::WFlags flags )
: QMainWindow( pParent, flags )
, ui( )
{
ui.textbox->setContextMenuPolicy( Qt::CustomContextMenu );
connect( ui.textbox, SIGNAL( customContextMenuRequested( QPoint ) ),
this, SLOT( onTextboxCustomContextMenuRequested( QPoint ) ) );
}
void MainWindow::onTextboxCustomContextMenuRequested( QPoint p )
{
// Start with the standard menu.
QMenu * pMenu = ui.textbox->createStandardContextMenu();
QAction * pAction;
// Clear.
// Because QPlainTextEdit::clear() is a slot method, I can connect directly to it.
pAction = new QAction( "Clear", this );
connect( pAction, SIGNAL( triggered() ), ui.textbox, SLOT( clear() ) );
pMenu->addAction( pAction );
// Show the menu.
QPoint q = ui.textbox->mapToGlobal( p );
pMenu->exec( q );
// The menu's ownership is transferred to me, so I must destroy it.
delete pMenu;
}

Getting information of clicked button (Qt)

I'm making the board game Puerto Rico in C++ and Qt. One of the features will be that after they've chosen the Major Role (button 1) each player (3 players in total) kan build a building. So i have a button for each building, is there a way that i get the information (like the name of the button) when the player clicked on it?
Kind regards
If you connect a signal of QPushButton to a slot, you can call sender() inside the slot to get the object which sent the signal.
Example slot code:
void MainWindow::onButtonPress()
{
QObject* senderObj = sender();
if (senderObj->isWidgetType())
{
QPushButton* button = qobject_cast<QPushButton*>(senderObj);
if (button)
{
// button is the QPushButton who emmited this signal
}
}
}
If you created building1Button, building2Button, building3Button buttons in the designer, you can try the followings.
In your class constructor you need to connect the clicked() SIGNAL from all building buttons to the same SLOT.
Game::Game()
{
// ...
connect( ui->building1Button, SIGNAL( clicked() ), this, SLOT( onBuildingClicked() ) );
connect( ui->building2Button, SIGNAL( clicked() ), this, SLOT( onBuildingClicked() ) );
connect( ui->building3Button, SIGNAL( clicked() ), this, SLOT( onBuildingClicked() ) );
// ...
}
And in that SLOT you can use sender() function to check which button was clicked.
void Game::onBuildingClicked()
{
QPushButton* clickedButton = qobject_cast< QPushButton* >( sender() );
if ( clickedButton )
{
const QString clickedBuilding = clickedButton->text();
const QString clickedButtonName = clickedButton->objectName();
}
}

Qt c++ QSystemTrayIcon not on tray, windows 7

what am i doing wrong? Program runs and compiles but icon is not on tray.
My OS is Windows 7.
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow( QWidget * parent )
: QMainWindow( parent )
, ui( new Ui::MainWindow )
{
QMenu * trayIconMenu;
trayIconMenu = new QMenu();
QSystemTrayIcon tray;
QIcon icon( ":/ok.png" );
tray.setIcon( icon );
tray.setContextMenu( trayIconMenu );
tray.show();
ui->setupUi( this );
}
MainWindow::~MainWindow()
{
delete ui;
}
The problem is that your QSystemTrayIcon destroys as soon as the execution exists your MainWindow constructor. You should rather do this:
MainWindow::MainWindow( QWidget * parent )
: QMainWindow( parent ),
ui( new Ui::MainWindow )
{
QMenu * trayIconMenu = new QMenu();
QSystemTrayIcon *tray = new QSystemTrayIcon(QIcon( ":/ok.png" ), this);
tray->setContextMenu( trayIconMenu );
tray->show();
ui->setupUi( this );
}

How do I get the currently visible text from a QTextEdit or QPlainTextEdit widget?

It seems like this would be a common thing to do, but I can't find how.
I have a QTextEdit or QPlainTextEdit widget with a bunch of text. Enough that scrolling is necessary.
I want another widget to give some information about the currently visible text. To do this, I need to know
when the visible text changes
what's the text?
I see that QPlainTextEdit has the method firstVisibleBlock, but it's protected. This tells me that it's not really something I should be using in my application. I wouldn't otherwise need to subclass from the edit window.
I also see that there's the signal updateRequest but it's not clear what I do with the QRect.
How do I do it or where do I find a hint?
I've written a minimal program that as two QTextEdit fields. In the left field you write and the text you are writing is shown in the second text edit too. You get the text of a QTextEdit by using toPlainText() and the signal is textChanged().
I've tested it and what you write in m_pEdit_0 is shown in "real-time" in m_pEdit_1.
main_window.hpp
#ifndef __MAIN_WINDOW_H__
#define __MAIN_WINDOW_H__
#include <QtGui/QtGui>
#include <QtGui/QMainWindow>
#include <QtGui/QApplication>
class main_window : public QMainWindow
{
Q_OBJECT
public:
main_window( QWidget* pParent = 0 );
~main_window();
public Q_SLOTS:
void on_edit_0_text_changed();
private:
QHBoxLayout* m_pLayout;
QTextEdit* m_pEdit_0;
QTextEdit* m_pEdit_1;
};
#endif // !__MAIN_WINDOW_H__
main_window.cpp
#include "main_window.hpp"
main_window::main_window( QWidget *pParent ) : QMainWindow( pParent )
{
m_pEdit_0 = new QTextEdit( this );
m_pEdit_1 = new QTextEdit( this );
connect( m_pEdit_0, SIGNAL( textChanged() ), this, SLOT( on_edit_0_text_changed() ) );
m_pLayout = new QHBoxLayout;
m_pLayout->addWidget( m_pEdit_0 );
m_pLayout->addWidget( m_pEdit_1 );
QWidget* central_widget = new QWidget( this );
central_widget->setLayout( m_pLayout );
setCentralWidget( central_widget );
}
main_window::~main_window()
{
}
void main_window::on_edit_0_text_changed()
{
m_pEdit_1->setText( m_pEdit_0->toPlainText() );
}
main.cpp
#include "main_window.hpp"
int main( int argc, char* argv[] )
{
QApplication a(argc, argv);
main_window mw;
mw.show();
return a.exec();
}
Edit:
This would work too, but would lack in performance for huge documents:
void main_window::on_edit_0_text_changed()
{
QStringList text_in_lines = m_pEdit_0->toPlainText().split( "\n" );
m_pEdit_1->clear();
for( int i = 0; i < text_in_lines.count(); i++ )
{
m_pEdit_1->append( text_in_lines.at( i ) );
}
}