I am new in qt I want to create a button when I right click
There is my code:
void MainWindow::right_clicked(QMouseEvent *event)
{
if(event->button() == Qt::RightButton)
{
QPushButton *item = new QPushButton();
item->setIcon(QIcon(":/images/7928748-removebg-preview(1).ico"));
item->setIconSize(QSize(32, 32));
item->setGeometry(QRect(QPoint(event->x(), event->y()), QSize(32, 32)));
}
}
But nothing appears
To capture any mouse event in a QWidget you must override the mousePressEvent method.
class MainWindow : public QMainWindow
{
Q_OBJECT
protected:
void mousePressEvent(QMouseEvent *event);
};
And in the mainwindow.cpp, implement it as follows:
void MainWindow::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::RightButton) {
// make mainwindow parent of this button by passing "this" pointer
QPushButton *item = new QPushButton(QIcon(":/images/close-button-icon"), "", this);
// set button position to the location of mouse click
item->setGeometry(QRect(QPoint(event->x()-16, event->y()-16), QSize(32, 32)));
item->show();
}
}
If you don't save the pointer to QPushButton, then you will not be able to use it afterwards.
Related
I have a table created with QTableWidget. I want to copy the cell's content (data) with right click. I've searched the web but haven't found anything that works for the right click event. How can I achieve this?
You should implement your own TableWidget class and override mousePressEvent() method:
class MyTableWidget : public QTableWidget
{
Q_OBJECT
public:
explicit MyTableWidget(QWidget *parent = nullptr)
: QTableWidget(parent)
{}
void mousePressEvent(QMouseEvent *event) override {
QTableWidget::mousePressEvent(event);
if(event->button() == Qt::RightButton) {
if(currentItem() == nullptr) {
return;
}
QClipboard *clipboard = QGuiApplication::clipboard();
clipboard->setText(currentItem()->text());
}
}
};
I'm trying to create a widget which, when shown, it will intercept any mouse clicks, process them, but then forward the click to the widget that was under the mouse when it was clicked. I've created a class that represents this widget; all it does for now is capture mouse release events, hide itself and post the event to the widget the click was intended for using QApplication::postEvent:
class Overlay : public QWidget
{
Q_OBJECT
public:
Overlay(QWidget* parent)
: QWidget(parent){}
protected:
void mouseReleaseEvent(QMouseEvent* event)
{
hide();
auto child = parentWidget()->childAt(event->pos()); // get the child widget the event was intended for
auto e = new QMouseEvent(*event);
if(child) QCoreApplication::postEvent(child, e); // why doesn't this have any effect?
event->accept();
}
void paintEvent(QPaintEvent* event)
{
QPainter p(this);
p.fillRect(rect(), QColor(0,0,0,150));
}
};
Unfortunately, the call to postEvent doesn't seem to have any effect at all. Here is an example where I'm setting up some child widgets; clicking on any widget will print something out:
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr)
{
m_overlay = new Overlay(this);
m_overlay->hide();
auto button = new QPushButton("Add overlay");
auto button2 = new QPushButton("PushButton");
auto list = new QListWidget();
list->addItems(QStringList() << "item1" << "item2" << "item3");
connect(list, &QListWidget::itemClicked, [](const QListWidgetItem* item)
{
qDebug() << item->text();
});
connect(button2, &QPushButton::clicked, []()
{
qDebug() << "Button clicked";
});
connect(button, &QPushButton::clicked, [this]()
{
m_overlay->setGeometry(rect());
m_overlay->raise();
m_overlay->show();
});
auto layout = new QVBoxLayout(this);
layout->addWidget(list);
layout->addWidget(button);
layout->addWidget(button2);
}
public:
~Widget(){}
private:
Overlay* m_overlay;
};
I've confirmed that clicks on the overlay are captured and the overlay is hidden as intended but the event is not propagated to the underlying widget. Using QApplication::sendEvent doesn't work either. What am I missing?
Using Qt 5.15.1 on MacOS 11.2.3. Thanks
I'm struggeling with telling a QScitilla textEdit that is the main widget of my MainWindow app to accept showing a personalized context menu on right-clicking the mouse.
What works fine if I use a standard Qt5 textEdit fails if used with the QScintilla alternative. I tried it with defining a user menu from some actions:
void MainWindow::contextMenuEvent(QContextMenuEvent *event)
{
QMenu menu(this);
menu.addAction(cutAct);
menu.addAction(copyAct);
menu.addAction(pasteAct);
menu.exec(event->globalPos());
}
#endif // QT_NO_CONTEXTMENU
reacting on QContextMenuEvent, but the menu only shows up when I right-click an element of the MainWindow instead of the QScintilla textEdit. When I do within the textEdit, only the standard cut/copy/paste menu is shown.
How to implement that for QScintilla textEdit?
There are two methods:
Method 1: set Qt::CustomContextMenu for context menu policy of QScintilla text edit :
textEdit->setContextMenuPolicy( Qt::CustomContextMenu );
connect(textEdit, SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(ShowContextMenu(const QPoint &)));
}
void MainWindow::ShowContextMenu(const QPoint &pos)
{
QMenu contextMenu(tr("Context menu"), this);
QAction action1("Action 1", this);
connect(&action1, &QAction::triggered, this, []{
qDebug() << "On action 1 click !!!";
});
contextMenu.addAction(&action1);
contextMenu.exec(mapToGlobal(pos));
}
Method 2: Define a subclass of QScintilla then redefine the override function contextMenuEvent :
class MyQsciScintilla : public QsciScintilla
{
Q_OBJECT
public:
explicit MyQsciScintilla(QWidget *parent = nullptr);
void contextMenuEvent(QContextMenuEvent *event);
//....
};
void MyQsciScintilla::contextMenuEvent(QContextMenuEvent *event)
{
QMenu *menu = createStandardContextMenu();
menu->addAction(tr("My Menu Item"));
//...
menu->exec(event->globalPos());
delete menu;
}
I have a sub-class of QWidget that is a popup widget. I would like to add some animation when it shows and disappears. So I re-implemented showEvent(QShowEvent * event) and hideEvent and added some QPropertyAnimation in the functions. The showEvent works just fine for me but the hideEvent doesn't. Because
Hide events are sent to widgets immediately after they have been hidden.
Any idea about how to do it?
Update:
I don't think it's the right reason. When I use Nejat's solution. The show part works. But when I click outside the widget. It disappears immediately.
You should override QWidget::closeEvent() so when trying to close immediatly it will be ignored AND we start our animation and after finishing (QPropertyAnimation::finished()) we close the widget as normal.
Here is a demo to demonstrate:
class AnimatedWidget : public QWidget {
Q_OBJECT
Q_PROPERTY(qreal alpha READ alpha WRITE setAlpha)
public:
AnimatedWidget(QWidget* parent = nullptr) :QWidget{ parent }, opacityAnimation{ new QPropertyAnimation{this, "alpha",this} } {
setWindowFlags(windowFlags() | Qt::WindowFlags(Qt::FramelessWindowHint) | Qt::Tool);
auto pal = palette();
pal.setColor(QPalette::Background, Qt::cyan);
setAutoFillBackground(true);
setPalette(pal);
setFixedSize(200, 200);
}
qreal alpha() const {
return windowOpacity();
}
void setAlpha(qreal level) {
setWindowOpacity(level);
update();
}
protected:
void closeEvent(QCloseEvent* e) override {
if (opacityAnimation->currentValue().toReal() == 1.0) { // Ignore event + start animation
e->ignore();
startHide();
QObject::connect(opacityAnimation, SIGNAL(finished()), this, SLOT(onAnimationCallBack()), Qt::UniqueConnection);
} else {
e->accept();
if (!isHidden())
hide();
QWidget::close(); // necessary actions
}
}
public Q_SLOTS:
void show() {
startShow();
QWidget::show(); // necessary actions
}
private Q_SLOTS:
void onAnimationCallBack() {
if (opacityAnimation->currentValue().toReal() == 0.0) { // we're finished so let's really close the widget
QCloseEvent ev;
QApplication::sendEvent(this, &ev);
qApp->sendEvent(this, &ev);
}
}
void startHide() {
opacityAnimation->setStartValue(1.0);
opacityAnimation->setEndValue(0.0);
opacityAnimation->setDuration(1500);
opacityAnimation->start();
}
void startShow() {
opacityAnimation->setStartValue(0.0);
opacityAnimation->setEndValue(1.0);
opacityAnimation->setDuration(1500);
opacityAnimation->start();
}
private:
QPropertyAnimation* opacityAnimation = nullptr;
};
class Base : public QWidget {
public:
Base(QWidget* parent = nullptr) :QWidget{ parent }, widget{ new AnimatedWidget{} } {
}
private:
AnimatedWidget* widget;
protected:
void mouseReleaseEvent(QMouseEvent* e) override {
if (widget->isHidden())
widget->show();
else
widget->close();
QWidget::mouseReleaseEvent(e);
}
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Base base;
base.show();
return app.exec();
}
You can override the eventFilter in your widget and check for QEvent::Show and QEvent::Close events.
bool MyWidget::eventFilter(QObject * obj, QEvent * event)
{
if(obj == this && event->type() == QEvent::Show)
{
//about to show
}
else if(obj == this && event->type() == QEvent::Close)
{
//about to close
}
return false;
}
You should also install the event filter in the constructor by:
this->installEventFilter(this);
I am doing something like this:
MyClass::MyClass(QWidget *parent) : QLabel(parent)
{
this->MyMenu = new QMenu();
QAction* act_del = new QAction(MyMenu);
act_delete->setText("MyAction");
MyMenu->addAction(act_del);
QObject::connect(act_del,SIGNAL(triggered()),this,SLOT(MySlot()));
}
void MyClass::MySlot()
{
//Not called
}
Any suggestion on when the SIGNAL is triggered the SLOT is not called. Here is where the menu is displayed:
void MyClass::contextMenuEvent(QContextMenuEvent *ev)
{
QPoint globalPos = this->mapToGlobal(ev->pos());
QAction* selectedItem = MyMenu->exec(globalPos);
if (selectedItem)
{
}
else
{
// nothing was chosen
}
}
Any suggestions on why the SLOT is not called?
MyClass needs to contain the Q_OBJECT macro for the signal-slot connections to work.