I have 10 Qlabels with an image on each. When i click on a label, its image should be cleared. I am able to identify which label was clicked theorotically, using the pixel clicked and size of each image. But how to use that information?
Eg. each label has dimension 100*100, the first label starting from 0,0. if pixel clicked is 250,50, i know that the third label was clicked, but how to use this to clear the label.
Im stuck.
There are a few ways how to implement it.
First. I would recommend to use a new class that inherits QLabel and overloads mouseReleaseEvent() handler where you just call clear() method. In this case the label will detect the mouse clicks itself and will clear its content internally.
class SelfClearingLabel : public QLabel
{
public:
using QLabel::QLabel;
protected:
void mouseReleaseEvent(QMouseEvent * event)
{
if (event->button()==Qt::LeftButton)
// process only clicks on the left button
{
clear();
}
QLabel::mouseReleaseEvent(event);
}
};
Second. You can catch mouseReleaseEvent() in your top widget and iterate over all of your child QLabel widgets and check which one is currently under mouse and clear the one. If you have other labels on this widget that shouldn't be cleared on mouse clicks then you can add some property to the QLabels that are under your interest.
void SomeTopFrame::createImageLabels(int count)
{
for (int i=0;i<count;i++)
{
QLabel* label=new QLabel(this);
label->setProperty("clear_on_click",true);
// assume that labels are added to layout *m_labelsLayout;
m_labelsLayout->addWidget(label);
}
}
void SomeTopFrame::mouseReleaseEvent(QMouseEvent * event)
{
if (event->button()==Qt::LeftButton)
// process only clicks on the left button
{
QList<QLabel*> labels=findChildren<QLabel*>();
foreach (QLabel* label, labels)
{
if (label->property("clear_on_click")&&label->underMouse())
{
label->clear();
break;
}
}
}
QFrame::mouseReleaseEvent(event);
}
It is a sample code just to show the principle. In production you can add a check that mouseReleaseEvent() is on the same widget as the mousePressEvent() to avoid triggering on drag and drop events.
Create the custom class that inherit QLabel :
ClickableLabel.h
class ClickableLabel : public QLabel
{
Q_OBJECT
public:
explicit ClickableLabel( const QString& text="", QWidget* parent=0 );
~ClickableLabel();
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent* event);
};
ClickableLabel.cpp
ClickableLabel::ClickableLabel(const QString& text, QWidget* parent)
: QLabel(parent)
{
setText(text);
}
ClickableLabel::~ClickableLabel()
{
}
void ClickableLabel::mousePressEvent(QMouseEvent* event)
{
emit clicked();
}
Just connect all labels clicked signal to following slot :
MyClass::labelClicked()
{
ClickableLabel *label = (ClickableLabel*)QObject::sender;
if(label)
label->clear();
}
Related
I have QDialog that contains few buttons and a QTextEdit.
after writing something in the QTextEdit, I press tab in order to get to one of the buttons, but when I pressing tab, a tab space is added to the QTextEdit. How can I change this behavior?
You can use setTabChangesFocus method of QTextEdit:
yourTextEdit.setTabChangesFocus(true);
You can subclass QTextEdit and override the keyPressEvent to intercept the tab key. Then, use nextInFocusChain to determine the next focus widget and call setFocus on it
Outline:
class MyTextEdit : public QTextEdit
{
public:
MyTextEdit(QWidget *parent = 0) : QTextEdit(parent) {}
protected:
void keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Tab) {
nextInFocusChain()->setFocus(Qt::TabFocusReason);
} else {
QTextEdit::keyPressEvent(e);
}
}
};
I have a QGraphicsView with a bigger QGraphicsScene that can be dragged.
In the QGraphicsScene I have a subclassed QGraphicsItem (TestItem) that displays a QGraphicsPixmapItem, which can have random shapes.
(I don't use QGraphicsPixmapItem directly because of extra functionality to be implemented in the future)
I want this item to be movable, but only if the user presses within the shape of the item. If outside the shape, but still inside the boundingRectangle, I want the scene behind it to be dragged. This because the boundingRectangle can be much bigger than the shape and the user doesn't see it, so it would be weird trying to drag the scene near the Pixmap and it not working.
This is my subclassed item:
TestItem::TestItem(QPointF position, QPixmap testImage, double width,
double length, QGraphicsItem * parent):
QGraphicsItem(parent),
m_boundingRect(QRectF(0,0,5, 5)),
m_dragValid(false),
m_path(QPainterPath()),
mp_image(new QGraphicsPixmapItem(this))
{
setBoundingRect(QRectF(0,0,width,length));
setPos(position - boundingRect().center());
setFlag(QGraphicsItem::ItemIsMovable);
mp_image->setPixmap(testImage.scaled(width, length));
m_path = mp_image->shape();
}
QPainterPath TestItem::shape()
{
return m_path;
}
QRectF TestItem::boundingRect() const
{
return m_boundingRect;
}
void TestItem::setBoundingRect(QRectF newRect)
{
prepareGeometryChange();
m_boundingRect = newRect;
}
I've tried overriding the mouse events like this, but all it brings me is no functionality at all when outside the shape but inside the bounding rectangle
void TestItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(shape().contains(event->pos()))
{
QGraphicsItem::mousePressEvent(event);
m_dragValid = true;
}
}
void TestItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseMoveEvent(event);
}
void TestItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseReleaseEvent(event);
m_dragValid = false;
}
which of course makes sense, but I wouldn't know how to implement the dragging of the scene, since it's the scene itself that sends the mouse events to the graphics item.
(My QGraphicsView is setup to DragMode QGraphicsView::ScrollHandDrag)
Anyone have ideas?
I figured it out. I only needed to add a event->ignore(); to my mouse events.
void TestItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if(shape().contains(event->pos()))
{
QGraphicsItem::mousePressEvent(event);
m_dragValid = true;
}
else
event->ignore();
}
void TestItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseMoveEvent(event);
else
event->ignore();
}
void TestItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if(m_dragValid)
QGraphicsItem::mouseReleaseEvent(event);
else
event->ignore();
m_dragValid = false;
}
You just need to enable QGraphicsItem::ItemClipsToShape flag:
The item clips to its own shape. The item cannot draw or receive mouse, tablet, drag and drop or hover events outside its shape. It is disabled by default.
I have third party widget which provides me some context menu. Lets say cut, copy paste, select all.
Now I just want to modify only the paste functionality of the existing context menu. I know that I can implement whole context menu from scratch in the contextMenuEvent. But I do not want to do that as I am satisfied with other context menu actions, and just want to modify only the paste functionality.
I am using QT 4.8 on Mac OSX.
If such a thing is not possible at the moment can someone give me link/reference for that ? So that I can satisfy my stakeholders.
Edit: To be more clearer on what I am trying to do is, disable the paste context menu for some reason, and want to enable it later on depending on the situation/events.
I'm not sure that it can be done in a common way.
Here is a tricky solution:
In contextMenuEvent create a queued call to some slot:
QMetaObject::invokeMethod(this, "patchMenu", Qt::QueuedConnection);
Get visible windows in the slot and find QMenu. Get actions out of it and enable/disable them:
Q_SLOT patchMenu()
{
QWidgetList widgets = QApplication::topLevelWidgets();
foreach (QWidget* widget, widgets)
{
if (QMenu* menu = qobject_cast<QMenu*>(widget))
{
QList<QAction*> actions = menu->actions();
// here you can either get an action by index actions[5]
// or search the action by text
actions;
}
}
}
EDIT:
Here is a working example which demonstrates this approach:
window.h
#pragma once
#include <QtGui>
class Window: public QMainWindow
{
Q_OBJECT
public:
Window(QWidget *parent = 0);
};
class A : public QWidget
{
public:
virtual void contextMenuEvent(QContextMenuEvent* e);
};
class B : public A
{
Q_OBJECT;
public:
virtual void contextMenuEvent(QContextMenuEvent*);
Q_SLOT void patchMenu();
};
window.cpp
#include "window.h"
Window::Window(QWidget *parent) : QMainWindow(parent)
{
setCentralWidget(new B());
}
void B::patchMenu()
{
QWidgetList widgets = QApplication::topLevelWidgets();
foreach (QWidget* widget, widgets)
{
if (QMenu* menu = qobject_cast<QMenu*>(widget))
{
QList<QAction*> actions = menu->actions();
// here you can either get an action by index actions[5]
// or search the action by text
actions;
}
}
}
void B::contextMenuEvent(QContextMenuEvent* e)
{
QMetaObject::invokeMethod(this, "patchMenu", Qt::QueuedConnection);
A::contextMenuEvent(e);
}
void A::contextMenuEvent(QContextMenuEvent* e)
{
QMenu menu;
QAction* action = new QAction(QIcon(), "text", &menu);
menu.addAction(action);
menu.exec(e->globalPos());
}
I have a QLineEdit widget in my menubar which shows the text "search by ID" by default. How can I implement a MouseClicked event handler for the QLineEdit, such that when I click on the LineEdit widget, the default text is cleared and user can enter the text that he wants to search?.
so far
#ifndef SEARCH_H
#define SEARCH_H
#include<QLineEdit>
class search : public QLineEdit
{
signals:
void clicked();
protected:
void mousePressEvent(QMouseEvent *);
};
#endif
You just need to connect QLineEdit::mousePressEvent ( QMouseEvent * e ) signal with function. When this signal will be emited, clear QLineEdit in your function. Simply, isn't it?
EDIT
Or if u have
void mousePressEvent(QMouseEvent *);
in your widget, all what you need is write definition for that method. When user press mouse over QLineEdit, this function will be invoked. Like:
void search::mousePressEvent(QMouseEvent *e)
{
myQLineEdit->setText("");
}
EDIT 2
Then try to do it this way:
class YourWidget : public QLineEdit
{
Q_OBJECT
protected:
void focusInEvent(QFocusEvent* e);
};
and
void YourWidget::focusInEvent(QFocusEvent* e)
{
if (e->reason() == Qt::MouseFocusReason)
{
myQLineEdit->setText("");
}
// You might also call the parent method.
QLineEdit::focusInEvent(e);
}
You'll want to use the QLineEdit::placeholderText property. It shows a grey text which disappears when the user starts editing it (i.e. when it gains focus).
QLineEdit * edit = new QLineEdit;
edit->setPlaceholderText("Search by ID");
I want to implement a widget (with some edit boxes and sliders) that would open beneath or next to a button ("Opener") when I hover it. The key is it's a temporary widget - as soon as it loses focus, I want it gone. Also, I want it to pop up right next to the Opener, ideally pointing an arrow to Opener.
So, it's basically a tooltip. But it needs to be a widget with buttons and sliders and stuff like that. Is there a clever way to implement it without making a custom widget and writing handlers for all the mouse and focus events and recomputing its ideal position every time I open it or the Opener moves?
class OpenerButton : public QPushButton
{
public:
OpenerButton(QWidget * parent = 0);
protected:
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
};
OpenerButton::OpenerButton(QWidget * parent)
: QPushButton(parent)
{
//Do necessary initializations For ex:set a menu for opener button
}
void OpenerButton::leaveEvent(QEvent * e)
{
//hide the popup_menu
}
void OpenerButton::enterEvent(QEvent * e)
{
//Show the menu
//You can use animation for ex:
Popup_menu=new Popup_Dialog(this);//Popup_Dialog is a dialog containing all your widgets
QPropertyAnimation *animation = new QPropertyAnimation(Popup_menu,"geometry");
animation->setDuration(500);
animation->setDirection(QAbstractAnimation::Forward);
QRect startRect(Rect_Relative_to_Opener_Button);
QRect endRect(Shifted_Rect_Relative_to_Opener_Button);
animation->setStartValue(startRect);
animation->setEndValue(endRect);
animation->start();
}
Enterevent is called when the mouse cursor enters the widget. Similarly leaveevent when mouse cursor leaves the widget.