I have a QPushButton in QT that I need to have redirect to a website, currently the button does not go anywhere when I inherited it. I have never worked with QT before so am looking for what would need to be done to make this button redirect to a URL when hit.
Right now the properties for it have
QObject
QWidget
QAbstractButton
QPushButton
Please help :)
You can extend QPushButon:
#include <QDesktopServices>
#include <QUrl>
#include "LinkButton.h"
LinkButton::LinkButton(QWidget *parent) : QPushButton(parent) {
this->setFlat(true);
connect(this, SIGNAL(clicked()), this, SLOT(slotOpenUrl()));
}
void LinkButton::setUrl(QString url) {
this->url = url;
}
void LinkButton::slotOpenUrl() {
QDesktopServices::openUrl(QUrl(this->url));
}
Related
This question already has an answer here:
Qt Widgets and derived classes
(1 answer)
Closed 3 years ago.
I am trying to make an application with a QGraphicsView in it. I tried to get the position of a mouse when the mouse was pressed with QGraphicsSceneMouseEvent, but it doesn't seem to work. The entire function is never called when I press the mouse.
I would like to make an application that can load an image into the QGraphicsView and then when you press the mouse button, it should add a small circle.
This is my code:
dialog.cpp:
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
ui->graphicsView = new GraphicsView();
}
Dialog::~Dialog()
{
delete ui;
}
graphicsview.h:
#ifndef GRAPHICSVIEW_H
#define GRAPHICSVIEW_H
#include <QGraphicsView>
#include <QMouseEvent>
#include <QDebug>
class GraphicsView : public QGraphicsView
{
public:
GraphicsView();
protected:
void mousePressEvent(QMouseEvent *event) override;
private:
QGraphicsScene *scene;
};
#endif // GRAPHICSVIEW_H
graphicsview.cpp:
#include "graphicsview.h"
GraphicsView::GraphicsView()
{
scene = new QGraphicsScene();
this->setScene(scene);
}
void GraphicsView::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
qDebug() << "The left button was pressed!";
}
}
You're almost there.
Just change GraphicsView::GraphicsView() to:
GraphicsView::GraphicsView(QWidget *parent=nullptr) : QGraphicsView(parent) {}
and change ui->graphicsView = new GraphicsView(); to
QVBoxLayout *verticalLayout = new QVBoxLayout(this);
verticalLayout->addWidget(new GraphicsView(this));
This will make the graphics view a parent of the dialog. Make sure that your dialog doesn't have anything in it when you add the code above. Alternatively, you can add a vertical layout to the dialog in your dialog.ui file and do
ui->verticalLayout->addWidget(new GraphicsView(this));
I believe that solves your problem. Respond if you still have any issues.
Make sure you always have a parent parameter. Without it, you're not telling your program where it's supposed to add your widget.
I am trying to make a helper with QTextBrowser. As I understood, home(), backward() and forward() are already implemented in QTextBrowser and required only connections to the buttons. Below there is .h and .cpp files
#ifndef HELPWINDOW_H
#define HELPWINDOW_H
#include <QDialog>
namespace Ui {
class HelpWindow;
}
class HelpWindow : public QDialog
{
Q_OBJECT
public:
explicit HelpWindow(QWidget *parent = 0);
~HelpWindow();
private slots:
private:
Ui::HelpWindow *ui;
};
#endif // HELPWINDOW_H
and
#include "helpwindow.h"
#include "ui_helpwindow.h"
HelpWindow::HelpWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::HelpWindow)
{
ui->setupUi(this);
// connection
connect(ui->pushButton_home,SIGNAL(clicked()),ui->textBrowser,SLOT(home()));
connect(ui->pushButton_forward,SIGNAL(clicked()),ui->textBrowser,SLOT(forward()));
connect(ui->pushButton_backward,SIGNAL(clicked()),ui->textBrowser,SLOT(backward()));
}
HelpWindow::~HelpWindow()
{
delete ui;
}
There is no any error message. It is possible to read and click the links inside QTextBrowser. Only there are no any actions with buttons. What do I miss here?
You need to call either one or both of the following properties
ui->textBrowser.setOpenLinks(true);
ui->textBrowser.setOpenExternalLinks(true);
and if you want filter or re-route the links at runtime
connect(ui->textBrowser, SIGNAL(sourceChanged(QUrl)), pointerToYourCode, SLOT(slotSourceChanged(QUrl)));
and implement
void YourCode::slotSourceChanged(const QUrl& url) {...}
I found why it did not work. The initial source should be specify:
ui->textBrowser->setSource(QUrl::fromLocalFile("help/index.html"));
Thank you, Jens for spending time.
(Update on 2019-01-02: Simplify my example)
I am working on a program that can minimize to tray and hide the main window. I expect the mainwindow to show when I click on the tray icon. This usually works, but I find that if the program minimizes to tray when I call QFileDialog::getOpenFileName() to select file without closing the dialog, I cannot activate the trayicon. Does anyone know how to solve it? I am using Qt 5.12.0 (was using Qt 5.9.0) on Manjaro Linux.
Minimal, Complete, and Verifiable example:
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h:
class MainWindow : public QMainWindow
{
Q_OBJECT
QSystemTrayIcon *trayIcon;
QMenu *trayContextMenu;
QAction *actShow;
QPushButton *button;
public:
MainWindow(QWidget *parent = 0);
protected:
void changeEvent(QEvent *);
private slots:
void click();
void trayIcon_activated(QSystemTrayIcon::ActivationReason reason);
void actShow_Triggered();
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
QPushButton *button = new QPushButton("button", this);
setCentralWidget(button);
connect(button,&QPushButton::clicked,
this,&MainWindow::click);
trayIcon=new QSystemTrayIcon;
trayIcon->setIcon(QIcon("hmtimer.png"));
trayContextMenu=new QMenu;
actShow=trayContextMenu->addAction(tr("Show"));
trayIcon->setContextMenu(trayContextMenu);
connect(actShow,&QAction::triggered,
this,&MainWindow::actShow_Triggered);
connect(trayIcon,&QSystemTrayIcon::activated,
this,&MainWindow::trayIcon_activated);
}
void MainWindow::changeEvent(QEvent *event)
{
if(event->type()==QEvent::WindowStateChange){
if(isMinimized()){
this->hide();
trayIcon->show();
}
}
else{
QMainWindow::changeEvent(event);
}
}
void MainWindow::click()
{
QFileDialog::getOpenFileName(this,QString());
}
void MainWindow::trayIcon_activated(QSystemTrayIcon::ActivationReason reason)
{
if(reason==3){ //reason==Trigger
this->show();
trayIcon->hide();
}
}
void MainWindow::actShow_Triggered()
{
this->show();
trayIcon->hide();
}
The example can be downloaded here
It seems that if the program minimizes to tray when QFileDialog::getOpenFileName(this,QString()) is not closed, I cannot make the mainwindow appear by click on the tray icon or right click to show the context menu.
How to reproduce:
Open the program
Click on the button to open file dialog
Minimize to tray
Try clicking and right-clicking on the tray icon
I found a way to show the main window. I can do this by double clicking the icon with the following code of MainWindow::trayIcon_activated:
void MainWindow::trayIcon_activated(QSystemTrayIcon::ActivationReason reason)
{
if(reason==QSystemTrayIcon::DoubleClick){
this->show();
trayIcon->hide();
}
}
I still don't know how to show the mainwindow with single click or show the context menu with right click. If anyone knows, please tell me.
EDIT: Seems that this no longer works. I tried both my previous example and new example. Don't know what is going wrong.
I have a push button that I'd like to change to a stop button when clicked. Currently the button's text says "auto fire", it runs an endless loop and it's text changes to "stop auto fire" when clicked. My problem is breaking the endless loop by clicking/pressing this button again after the text changes.
Code so far:
void Cpp_Fire::on_auto_fire_clicked()
{
while(true)
{
ui->auto_fire->setText("Stop Auto Fire");
on_manual_fire_clicked();
}
}
I tried inserting a different slot into the loop above that runs when after the button is pressed (it runs when the button is released to be precise) but I couldn't get it to work.
I know this could be done with signals/slots and a separate stop button but I'm unfamiliar with that method and I prefer the method I described.
The problem with your endless loop is that nothing else gets a chance to work.
One approach you could use is to use a QTimer with a short interval to call the on_manual_fire_clicked() method, then have the on_auto_fire_clicked() method be responsible for changing the text on the button and enabling / disabling the timer.
The ui should get enough time to respond to clicks etc if you do it that way.
edit:
For more info on using QTimer have a look at this page:
How to use QTimer
or this tutorial:
http://www.bogotobogo.com/Qt/Qt5_QTimer.php
Here's some code:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_clicked();
void timerslot();
private:
Ui::MainWindow *ui;
QTimer* myTimer;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QTimer>
#include<QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
myTimer = new QTimer(this);
myTimer->setInterval(500);
myTimer->setSingleShot(false);
connect(myTimer, SIGNAL(timeout()), this, SLOT(timerslot()));
myTimer->start();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::timerslot()
{
qDebug() << "timeslot";
}
void MainWindow::on_pushButton_clicked()
{
if ( this->myTimer->isActive() == true ) {
this->myTimer->stop();
ui->pushButton->setText("Start");
} else {
this->myTimer->start(500);
ui->pushButton->setText("Stop");
}
}
I hope you get the idea and can convert it to your needs.
I fully agree Michael's answer.
This will also affect the repaint! (Try to put some windows over your application, while in endless-loop: you should see repaint problems).
Don't use endless-loops, specially not within slots!
Try QTimer, or move object to a QThread.
While in such loop: Give GUI-Thread some time. You can call QCoreApplication::processEvents().. But be careful with this.
A simple (still poor) solution with QTimer could be:
(I found, Michael entered an example in his answer. - Use it.).
//have a QTimer 'timer' in the class, and a connect signal
//timer.timeout() to 'onSingleShotFired()'
void Cpp_Fire::on_auto_fire_clicked()
{
if ( ui->auto_fire->text() == "Stop Auto Fire" )
{
timer.stop();
ui->auto_fire->setText("Start Auto Fire");
}
else
{
//MSEC_AUTOFIRE_DELAY is the delay between the autofire-shots
timer.start( MSEC_AUTOFIRE_DELAY );
ui->auto_fire->setText("Stop Auto Fire");
}
}
I'm trying to get a QDateEdit to allow the QCalendarWidget to show when requested (rather than just on clicking the down arrow). For example, somewhere in my class I should be able to say:
ui.datepicker.showCalendar()
and it should load up the calendar that appears right below the date picker.
It looks like I need to sub-class QDateEdit, as this doesn't work:
QDateEdit *de = new QDateEdit();
de->calendarWidget()->show();
I've also tried sending keyboard commands as dictated when you go through the QDateTimeEdit.cpp source for Qt, but seems my keyboard shortcuts are disabled or something.
Any ideas on what I have to do to sub-class to get this to work? I was thinking of something like:
class MyDateEdit : QDateEdit
{
Q_OBJECT
protected:
void mouseEvent(QEvent *event) {
this.calendarWidget().show();
}
};
But alas that also doesn't seem to compile in or work correctly.
Enable "setCalendarPopup ( bool enable )" in QDateTimeEdit allows to popup the calendar
I was able to figure it out on my own - still no sure how to get QDateEdit to work properly, but I used a QLineEdit and it suited my needs. Just connect QCalendarWidget's "onClick(QDate)" to a slot you create that does a:
setText(date.toString("M/d/yyyy"));
ui->calendar->hide();
Then add an event filter to the QLineEdit using the "OnFocusIn" event that does a "ui->calendar->show();" See: Get a notification/event/signal when a Qt widget gets focus
#Rob S answer
You were right with event filter approach we would do same with QDateEdit.
I am writing the code which extends your approach with QDateEdit :
In mainwindow.h I created a QCalendar pointer (Using QtCreator)
Following is the code of mainwindow.cpp (I am giving out fullcode so that rookies like me can benifit from it)
Make sure you set buttonSymbol and calendarpopup property to false to make it work correctly
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCalendarWidget>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->dateEdit->setDate(QDate::currentDate());
widget=new QCalendarWidget(); //widget is QCalendar pointer
ui->verticalLayout->addWidget(widget);
widget->setWindowFlags(Qt::Popup); // we need widget to popup
ui->dateEdit->installEventFilter(this);
connect(widget,SIGNAL(clicked(QDate)),ui->dateEdit,SLOT(setDate(QDate)));
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == QEvent::InputMethodQuery)
{
if (object == ui->dateEdit)
{
if(widget->isVisible()==false && ui->dateEdit->calendarWidget()->isVisible()==false) // this done to avoid conflict
{
qWarning(QString().number(event->type()).toStdString().c_str());
qWarning(object->objectName().toLatin1().data());
widget->move(ui->dateEdit->mapToGlobal(QPoint(0,ui->dateEdit->height())));
widget->show();
}
}
}
return false;
}
OR :: Alternatively we can use QCalendarWidget provided by dateEdit, though its not much efficient as turing it to Popup will mess with its internal. Give it a shot if you want
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QCompleter>
#include <QCalendarWidget>
#include <QMouseEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->dateEdit->setDate(QDate::currentDate());
widget = ui->dateEdit->calendarWidget();
widget->setWindowFlags(Qt::Popup);
ui->dateEdit->installEventFilter(this);
//connecting widget with dateedit
ui->dateEdit->setButtonSymbols(QAbstractSpinBox::NoButtons);
ui->dateEdit->setCalendarPopup(true);
connect(widget,SIGNAL(clicked(QDate)),ui->dateEdit,SLOT(setDate(QDate)));
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *object, QEvent *event)
{
if (object == ui->dateEdit)
{
if (event->type() == QEvent::FocusIn || event->type() == QEvent::MouseButtonPress)
{
// WE NEED MOUSE EVENT TO AVOID INTERFERNCE WITH CALENDAR POPUP BUTTON SITUATED AT CORNER OF dateEdit WIDGET
if(widget->isVisible()==false && ( ((QMouseEvent* )event)->x()< (ui->dateEdit->width()-10)))
{
widget->move(ui->dateEdit->mapToGlobal(QPoint(0,ui->dateEdit->height())));
widget->show();
}
}
}
return false;
}
I'd like to offer option similar to #Dr. Xperience's answer that encapsulates calendar widget in QDateEdit subclass:
#include <QDateEdit>
#include <QCalendarWidget>
class DateEdit : public QDateEdit {
Q_OBJECT
public:
explicit DateEdit(QWidget *parent = nullptr);
protected:
virtual void focusInEvent(QFocusEvent *event) override;
private:
QCalendarWidget *calendar = new QCalendarWidget(this);
};
DateEdit::DateEdit(QWidget *parent) : QDateEdit (parent) {
setButtonSymbols(QAbstractSpinBox::NoButtons);
setCalendarPopup(false);
setDate(QDate::currentDate());
calendar->setWindowFlags(Qt::Popup);
connect(calendar, &QCalendarWidget::clicked, this, [&](const QDate &date) {
setDate(date);
calendar->hide();
});
}
void DateEdit::focusInEvent(QFocusEvent *event) {
if (!calendar->isVisible()) {
calendar->setSelectedDate(date());
calendar->move(mapToGlobal(QPoint(0, height())));
calendar->show();
}
return QDateEdit::focusInEvent(event);
}
Warning: If you place this widget using QtDesigner, it will override buttonSymbols and calendarPopup properties, so you have to set it manually to hide QDateEdit's buttons.
Here is my hacky approach to the issue. After fighting for quite a while to have something clean, I read the source code of QDateEditor (which in fact is just a simplified QDateTimeEditor) and it seems to be no clean solution. The following is code for toggle() rather than show(), but still:
// Enable the calendar popup
date_editor->setCalendarPopup(true);
// Show the calendar popup by default
// There seems to be no proper interface to achieve that
// Fake a mouse click on the right-hand-side button
QPointF point = date_editor->rect().bottomRight() - QPointF{5, 5};
QCoreApplication::postEvent(
date_editor,
new QMouseEvent(QEvent::MouseButtonPress, point, Qt::LeftButton,
Qt::LeftButton, Qt::NoModifier));
Using something like this you can keep relying on the editor's validation features.
BTW, another annoying thing about the built-in editor that makes a QLineEdit tempting is that (at least in my case) the keyboard cursor is not shown by default. This is very confusing. To solve this I did:
// Select a section so that the cursor is be visible
date_editor->setSelectedSection(QDateTimeEdit::DaySection);
This or course selects the day section of the date, but if you use keyboard arrows the selection vanished, but you can see the keyboard cursor.