I want to change the color of an ellipse when I move my mouse over it.
But I haven't found anything from reference and auto-complete from Qt Creator.
Do you guys know how to do it?
Some of my code:
void DrawingWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.fillRect(event->rect(), Qt::white);
for(int i = 0; i < pointList.size(); i++) {
if (pointList[i].x() >= 0 && pointList[i].y() >= 0)
painter.drawEllipse(pointList[i], 10, 10);
}
painter.drawLines(lineList);
m_mainWindow->updateCount();
}
Mouse press event handler:
void DrawingWidget::mousePressEvent(QMouseEvent *event) {
if (event->button() == Qt::LeftButton
&& event->buttons() == Qt::LeftButton) {
// DO STUFFF
}
}
Mouse move event handler:
void DrawingWidget::mouseMoveEvent(QMouseEvent *event) {
if (m_mainWindow->getSelectedTool() == MainWindow::moveVertexTool) {
m_x = event->x();
m_y = event->y();
if (isPointNear(m_x, m_y)) {
//STUFF
}
update();
}
}
}
Now I just need a mouse OVER event (handler).
I think what you are looking for are enter and leave events.
Use QWidget::underMouse() for check if the widget is under the mouse cursor.
For example:
void IconButton::paintEvent(QPaintEvent *)
{
QPainter painter(this);
// Note isDown should really use the active state but in most styles
// this has no proper feedback
QIcon::Mode mode = QIcon::Disabled;
if (isEnabled()) {
if (isDown())
mode = QIcon::Selected;
else
mode = underMouse() ? QIcon::Active : QIcon::Normal;
}
QPixmap pixmap = icon().pixmap(iconSize(), mode);
QRect pixmapRect = QRect(0, 0, pixmap.width(), pixmap.height());
pixmapRect.moveCenter(rect().center());
if (m_autoHide)
painter.setOpacity(m_iconOpacity);
painter.drawPixmap(pixmapRect, pixmap);
}
This value is not updated properly during drag and drop operations.
Related
I want to change the default tab widget close button and set my icon instead. The problem is that it draws the icon on the text. I want to draw the X to the right.
Code:
void AppTabBar::paintEvent(QPaintEvent *event)
{
QStylePainter painter(this);
QStyleOptionTab opt;
for (int i = 0; i < this->count(); i++) {
initStyleOption(&opt, i);
opt.text = painter.fontMetrics().elidedText(opt.text, Qt::ElideRight, 70);
painter.drawControl(QStyle::CE_TabBarTabShape, opt);
painter.save();
QSize s = opt.rect.size();
if (tabPos != AppTabPosition::Top && tabPos != AppTabPosition::Bottom) {
s.transpose();
}
QRect r(QPoint(), s);
r.moveCenter(opt.rect.center());
opt.rect = r;
QPoint c = tabRect(i).center();
painter.translate(c);
if (tabPos == AppTabPosition::Left) {
painter.rotate(90);
} else if (tabPos == AppTabPosition::Right) {
painter.rotate(270); //90 - left pos, 270 - right pos
}
painter.translate(-c);
painter.drawControl(QStyle::CE_TabBarTabLabel, opt);
painter.restore();
}
QWidget::paintEvent(event);
}
void AppTabStyle::drawPrimitive(QStyle::PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
{
if (element == PE_IndicatorTabClose) {
int size = proxy()->pixelMetric(QStyle::PM_SmallIconSize);
QIcon::Mode mode = option->state & State_Enabled ? (option->state & State_Raised ? QIcon::Active : QIcon::Normal) : QIcon::Disabled;
if (!(option->state & State_Raised) && !(option->state & State_Sunken) && !(option->state & QStyle::State_Selected)) {
mode = QIcon::Disabled;
}
QIcon::State state = option->state & State_Sunken ? QIcon::On : QIcon::Off;
QPixmap pixmap = QIcon(":/Icons/cross_icon.png").pixmap(size, mode, state);
proxy()->drawItemPixmap(painter, option->rect, Qt::AlignRight, pixmap);
} else {
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
}
Screenshot:
This issue only appears on the vertical tabs (AppTabPosition::Left or AppTabPosition::Right). Any ideas how to draw it to the right?
Edited (15.05.2021):
I have set setTabsClosable(false);, then created the TabBarLabel class and set it to setTabButton method. It closes the tabs but the issue with overlapping the tab text still exists:
Screenshot:
It is a lot of code, so I have created and uploaded to Mega the test example to illustrate this issue. Here is my test example: TabExample.zip (6kb)
Any ideas how to change position of tab bar close button? Thank you.
Thank you.
Finally! I have fixed the issue with vertical tab close button position.
Code:
if (tabPos != AppTabPosition::Top && tabPos != AppTabPosition::Bottom) {
s.transpose();
if (this->tabsClosable()) { // check if tab is closable
QRect optRect = opt.rect;
optRect.setX(90); // set X pos of close button
optRect.setY(optRect.y() + 8); // calcs the Y pos of close button
optRect.setSize(QSize(12, 12));
this->tabButton(i, QTabBar::RightSide)->setGeometry(optRect);
}
}
Here I do not change the default opt.rect but instead I copy it to new QRect. Then I change the size and position of optRect and finally set geometry to tabButtton .
Screenshot:
The issue is resolved.
I have QVector<QPoint> m_vertices; in my drawingwidget.h
class DrawingWidget: public QWidget {
Q_OBJECT
public:
DrawingWidget(MainWindow *parent = 0);
~DrawingWidget();
QVector<QPoint> m_vertices;
I trying to implement adding/deleting vertices on my mainwindow. I managed to make the add function, now it's should be easy to delete them, but i am a bit confused.
The main idea is, that i have a pop-up menu, where i can choose a "tool". I can add vertex, remove vertex, move vertex, add line, delete line. The idea is , when i choose for example "Add Vertex" then the "m_state" will change to "ADD_VERTEX_SELECTED" so i can only add vertices and nothing else.
enum DrawingWidgetState {
NO_TOOL_SELECTED,
ADD_VERTEX_SELECTED,
MOVE_VERTEX_SELECTED,
DELETE_VERTEX_SELECTED,
ADD_LINE_SELECTED,
DELETE_LINE_SELECTED
};
Drawing
void DrawingWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.fillRect(event->rect(), Qt::blue);
painter.setBrush(Qt::black);
for(int i = 0; i < m_vertices.size() ; i++) {
painter.drawEllipse(m_vertices[i], 20, 20);
}
MousePress event. On left click, I have to delete the vertex that I clicked on
void DrawingWidget::mousePressEvent(QMouseEvent *event) {
if(m_state == ADD_VERTEX_SELECTED) {
if(event->button() == Qt::LeftButton) {
//m_x = event->x();
//m_y = event->y();
//update();
QPoint point = event->pos();
m_vertices.append(point);
update();
}
}
if(m_state == DELETE_VERTEX_SELECTED) {
if(event->button() == Qt::LeftButton) {
m_vertices.clear();
}
}
}
How can i do that ?
This code uses std::find_if together with a lambda expression to find the closest point. You probably want to allow a bit more leeway than the exact circle radius, but that is up to you.
auto it = std::find_if(m_vertices.begin(), m_vertices.end(), [point = event->pos](QPoint v) {
auto d = v - point;
return QPoint::dotProduct(d, d) < 400; // dotProduct returns square of distance
});
if (it != m_vertices.end()) {
m_vertices.erase(it);
}
I have QVector<QPoint> m_vertices and QVector<QLine> in my drawingWidget.h
I currently trying to do a simple drawing tool, where I can add vertices and lines. I managed to draw multiple vertices on my "MainWindow", but I can't really understand, how can I implement a line between created vertices.
Basically I have two points created and by pressing the left mouse button on the first vertex and left mouse button on the second vertex... it's should create a line between them.
How can I do that?
void DrawingWidget::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.fillRect(event->rect(), Qt::blue);
painter.setBrush(Qt::black);
for(int i = 0; i < m_vertices.size() ; i++) {
painter.drawEllipse(m_vertices[i], 20, 20);
}
}
void DrawingWidget::mousePressEvent(QMouseEvent *event) {
if(m_state == ADD_VERTEX_SELECTED) {
if(event->button() == Qt::LeftButton) {
//m_x = event->x();
//m_y = event->y();
//update();
QPoint point = event->pos();
m_vertices.append(point);
update();
}
}
if(m_state == ADD_LINE_SELECTED) {
if(event->button() == Qt::LeftButton) {
QPoint Startpoint = event->x();
QPoint Endpoint = event->y();
}
}
}
You are almost there. You need to use QPainter::drawLine for this and pass the two consecutive mouse QPoints from m_vertices.
For example
void DrawingWidget::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.fillRect(event->rect(), Qt::blue);
painter.setPen(QPen(Qt::black, 3)); // width of the line
if(m_vertices.size() == 1) // for the first mouse click
painter.drawEllipse(m_vertices[0], 4, 4);
for(int i = 0; i < m_vertices.size()-1 ; i++)
{
const QPoint& point1 = m_vertices[i];
const QPoint& point2 = m_vertices[i+1];
// draw the mouse point
painter.drawEllipse(point1, 4, 4);
painter.drawEllipse(point2, 4, 4);
// draw the line
painter.drawLine(point1, point2);
}
}
I am building a Qt5 application that allows a user to draw a rubberband with his mouse over an image, to select certain area of the image for further processing.
I got my code to only allow the user to start drawing the rubberband, by subclassing a QLabel to a custom class (frame_displayer) which mousePressEvent() is overridden and thus be only invoked when the mouse press happens within the custom classed widget.
The problem is that when the initial click is inside the frame_displayer, mouseMoveEvent(), the function that I use to change the rubberband size accordingly, keeps getting called even when the mouse cursor has been dragged outside of the frame_displayer.
I have tried using leaveEvent() and enterEvent() to control a class boolean flag that codes inside mouseMoveEvent could rely on to know whether the cursor is still within the widget. However, both leaveEvent() and enterEvent() are only called while a mouse button is not being held, thus rendering them no use for constraining the rubberband.
Also, the underMouse() always return true, for a reason unknown to me.
Segment of frame_displayer.cpp
frame_displayer::frame_displayer(QWidget * parent) : QLabel(parent)
{
_rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
}
void frame_displayer::mousePressEvent(QMouseEvent *event)
{
_lastClickedBtn = event->button();
if (_lastClickedBtn == Qt::LeftButton)
{
_mouseOriginClickPoint = event->pos();
_rubberBand->setGeometry(QRect(_mouseOriginClickPoint, _mouseClickPoint));
_rubberBand->show();
}
}
void frame_displayer::mouseMoveEvent(QMouseEvent *event)
{
if(_rubberBand != nullptr)
{
if (this->underMouse())
{
if (_lastClickedBtn == Qt::LeftButton)
{
QPoint mouseCurrentPoint = event->pos();
_rubberBand->setGeometry(QRect(_mouseOriginClickPoint, mouseCurrentPoint).normalized());
}
}
}
}
void frame_displayer::mouseReleaseEvent(QMouseEvent *event)
{
_mouseOriginClickPoint = QPoint();
_lastClickedBtn = Qt::MidButton;
if(_rubberBand != nullptr)
{
_rubberBand->hide();
_rubberBand->clearMask();
}
}
void frame_displayer::leaveEvent(QEvent *event)
{
qDebug() << "Leaving";
}
void frame_displayer::enterEvent(QEvent *event)
{
qDebug() << "Entering";
}
Thanks in advance!
I think that's the expected behaviour. If you want to limit the extents of the rubber band then simply clamp them in the mouseMoveEvent override...
void frame_displayer::mouseMoveEvent(QMouseEvent *event)
{
if(_rubberBand != nullptr)
{
if (this->underMouse())
{
if (_lastClickedBtn == Qt::LeftButton)
{
QPoint mouseCurrentPoint = event->pos();
/*
* Clamp mouseCurrentPoint to the QRect of this widget.
*/
auto clamp_rect = rect();
mouseCurrentPoint.rx() = std::min(clamp_rect.right(), std::max(clamp_rect.left(), mouseCurrentPoint.x()));
mouseCurrentPoint.ry() = std::min(clamp_rect.bottom(), std::max(clamp_rect.top(), mouseCurrentPoint.y()));
_rubberBand->setGeometry(QRect(_mouseOriginClickPoint, mouseCurrentPoint).normalized());
}
}
}
}
I've got an application which handles zooming in/out using the mouse wheel with this event in Qt Creator.
cpp
void QNodeView::wheelEvent(QWheelEvent* event) {
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
// Scale the view / do the zoom
double scaleFactor = 1.15;
if(event->delta() > 0) {
// Zoom in
scale(scaleFactor, scaleFactor);
} else {
// Zooming out
scale(1.0 / scaleFactor, 1.0 / scaleFactor);
}
}
This is in the header file
h
protected:
//Take over the interaction
virtual void wheelEvent(QWheelEvent* event);
How can I add the ability to pan with the middle mouse button being pressed the user dragging the cursor?
I can post the project code if necessary just ask.
Thanks
Project files link (Qt Creator project)
https://www.dropbox.com/s/gbt4qqtdedltxek/QNodesEditor-master_01.zip?dl=0
At first, introduce some new member variables into your viewer class:
class QNodeView : public QGraphicsView
{
// ...
private:
int m_originalX = 0;
int m_originalY = 0;
bool m_moving = false;
};
Then reimplement mousePressEvent(), mouseMoveEvent(), and mouseReleaseEvent().
void QNodeView::mousePressEvent(QMouseEvent* event)
{
if (event->button() == Qt::MiddleButton)
{
// store original position
m_originalX = event->x();
m_originalY = event->y();
// set the "moving" state
m_moving = true;
}
}
void QNodeView::mouseMoveEvent(QMouseEvent* event)
{
if (m_moving)
{
// panning operates in the scene coordinates using x,y
QPointF oldp = mapToScene(m_originalX, m_originalY);
QPointF newp = mapToScene(event->pos());
QPointF translation = newp - oldp;
translate(translation.x(), translation.y());
m_originalX = event->x();
m_originalY = event->y();
}
}
void QNodeView::mouseReleaseEvent(QMouseEvent* event)
{
if (event->button() == Qt::MiddleButton)
{
m_moving = false;
}
}