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());
}
}
};
Related
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.
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 have 5 buttons in my window qt app. I would like to set a label text, which is a description for each process on hovering above the button. How can I do that?
We can use eventFilter for this.
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == (QObject*)ui->pushButton) {
if (event->type() == QEvent::Enter)
{
ui->label_3->setText("Your text");
}
else if (event->type() == QEvent::Leave){
//Clear text when mouse leaves
ui->label_3->setText("");
}
return QWidget::eventFilter(obj, event);
}
else return QWidget::eventFilter(obj, event);
}
QEvent::HoverEnter and QEvent::HoverLeave can do this for you. Set an event filter (https://doc.qt.io/qt-5/eventsandfilters.html) on your QPushButton and you are good to go.
Assuming you are using QPushButton in your UI, you can reimplement the following methods :
virtual void enterEvent(QEvent *e)
{
setText("mouse in");
}
virtual void leaveEvent(QEvent *e)
{
setText("mouse out");
}
I added an EventFilter to a QCompleter because I had the same problem as this person.
Now I want to add a left mouse button event if an item is clicked from the PopupCompletion.
I tried but I have no idea if I'm on the right track because im new to Qt.
eventfilter.h
class EventFilter : public QObject
{
Q_OBJECT
public:
EventFilter(QLineEdit* lineEdit, QObject* parent = NULL)
:QObject(parent)
,mLineEdit(lineEdit)
{ }
virtual ~EventFilter()
{ }
bool eventFilter(QObject* watched, QEvent* event);
private:
QLineEdit* mLineEdit;
};
eventfilter.cpp
#include "eventfilter.h"
bool EventFilter::eventFilter(QObject* watched, QEvent* event)
{
QAbstractItemView* view = qobject_cast<QAbstractItemView*>(watched);
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return ||
keyEvent->key() == Qt::Key_Enter ||
keyEvent->key() == Qt::Key_Tab)
{
mLineEdit->clear();
mLineEdit->setFocus();
view->hide();
return true;
}
}
if (event->type() == QEvent::MouseButtonPress)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::LeftButton)
{
mLineEdit->clear();
mLineEdit->setFocus();
view->hide();
return true;
}
}
return false;
}
mainwindow.h
#include "eventfilter.h"
class QCompleter;
class QLabel;
class QLineEdit;
class QWidget;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
private:
void createMenu();
QAbstractItemModel *modelFromFile(const QString& fileName);
QCompleter *completer;
QLabel *contentsLabel;
QLineEdit *lineEdit;
QWidget *widgetBox;
};
mainwindow.cpp
#include "mainwindow.h"
completer = new QCompleter(this);
completer->setModel(modelFromFile(":/resources/wordlist.txt"));
completer->setModelSorting(QCompleter::CaseInsensitivelySortedModel);
lineEdit->setCompleter(completer);
EventFilter *filter = new EventFilter(lineEdit);
completer->popup()->installEventFilter(filter);
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);