I am working on a paint program in QT5 C++ and I am trying to modify a function that draws a line to incorporate the 45 degree, horizontal or vertical special line that should be drawn if the shift key is clicked.
Below is what I have but for some reason the key handler is not working for me.
I received an error but I don't understand what I need to do to fix it attached below is the error and the code for the paint function that I've modified after that. I have wrapped the modification I did in comments for readability
void LineInstrument::paint(ImageArea &imageArea, bool isSecondaryColor, bool)
{
QPainter painter(imageArea.getImage());
if(isSecondaryColor)
{
painter.setPen(QPen(DataSingleton::Instance()->getSecondaryColor(),
DataSingleton::Instance()->getPenSize() * imageArea.getZoomFactor(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
}
else
{
painter.setPen(QPen(DataSingleton::Instance()->getPrimaryColor(),
DataSingleton::Instance()->getPenSize() * imageArea.getZoomFactor(),
Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
}
if(mStartPoint != mEndPoint) // here is where the line is drawn
{
painter.drawLine(mStartPoint, mEndPoint); // let the line be drawn
// my modifications start here
if (QApplication::keyboardModifiers().testFlag(Qt::ShiftModifier) == true) { // check if shift key is active
QMouseEvent *mouse;
if (mouse->pos().x() > mouse->pos().y()){
// transform to a horizontal line
painter.save(); // save current painter state
painter.rotate(180);
painter.restore(); // restores painter state
}
else if (mouse->pos().x() < mouse->pos().y()){
// transfomr to a vertical line
painter.save();
painter.rotate(90);
painter.restore();
}
else{
// transform to a 45 degree line
painter.save();
painter.rotate(45);
painter.restore();
}
}// and end here
}
if(mStartPoint == mEndPoint)
{
painter.drawPoint(mStartPoint);
}
imageArea.setEdited(true);
// int rad(DataSingleton::Instance()->getPenSize() + round(sqrt((mStartPoint.x() - mEndPoint.x()) *
// (mStartPoint.x() - mEndPoint.x()) +
// (mStartPoint.y() - mEndPoint.y()) *
// (mStartPoint.y() - mEndPoint.y()))));
// mPImageArea->update(QRect(mStartPoint, mEndPoint).normalized().adjusted(-rad, -rad, +rad, +rad));
painter.end();
imageArea.update();
}
The error is pretty clear.
QMouseEvent *mouse; - you declare a pointer to the a QMouseEvent, but where is it instantiated? This is only a pointer which points to something.
If you want to handle mouse events you probably have to overload some kind of widget's mouse event (mouseMoveEvent, mousePressEvent, etc.). Those will provide you a valid QMouseEvent input.
Related
I want to draw a triangle like this
I think I have to change these part of my codes
glBegin(GL_LINES);
glVertex2f(point[0][0], point[0][1]);
glVertex2f(point[1][0], point[1][1]);
glEnd();
and my mouse button down codes are like this
if (action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT)
{
inputMode = InputMode::DRAGGING; // Dragging starts
point[0][0] = xw; point[0][1] = yw; // Start point
point[1][0] = xw; point[1][1] = yw; // End point
}
How I have to do?
You need some global variables for 3 points and one index that is telling you which point you actually edit ...
float point[3][2];
int ix=0;
the render change to
glBegin(GL_LINE_LOOP); // or GL_TRIANGLE
glVertex2fv(point[0]);
glVertex2fv(point[1]);
glVertex2fv(point[2]);
glEnd();
now I do not code in GLFW but you need to change the onclick events to something like:
static bool q0 = false; // last state of left button
bool q1 = (action == GLFW_PRESS && button == GLFW_MOUSE_BUTTON_LEFT); //actual state of left button
if ((!q0)&&(q1)) // on mouse down
{
if (ix==0) // init all points at first click
{
point[0][0]=xw; point[0][1]=yw;
point[1][0]=xw; point[1][1]=yw;
point[2][0]=xw; point[2][1]=yw;
}
}
if (q1) // mouse drag
{
point[ix][0]=xw; point[ix][1]=yw;
}
if ((q0)&&(!q1)) // mouse up
{
point[ix][0]=xw; point[ix][1]=yw;
ix++;
if (ix==3)
{
ix=0;
// here finalize editation for example
// copy the new triangle to some mesh or whatever...
}
}
q0=q1; // remember state of mouse for next event
This is my standard editation code I use in my editors for more info see:
Does anyone know of a low level (no frameworks) example of a drag & drop, re-order-able list?
I am not sure about the q1 as I do not code in GLFW its possible you could extract the left mouse button state directly with different expression. the q0 does not need to be static but in such case it should be global... Also its possible the GLFW holds such state too in which case you could extract it similarly to q1 and no global or static is needed for it anymore...
I created my own classes (view and scene) to display image and objects I added to it, even got zoom in/out function implemented to my view, but now I have to add new functionality and I don't even know how to start looking for it.
Whenever I press the scroll button of my mouse and hold it - I wish to move around the scene, to see different parts of it - just like I would with sliders. It is supposed to be similar to any other program allowing to zoom in/out to image and move around zoomed picture to see different parts of it.
Unfortunately - I don't even know how to look for some basic, because "moving" and similar refer to dragging objects around.
EDIT 1
void CustomGraphicView::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() == Qt::MidButton)
{
setTransformationAnchor(QGraphicsView::AnchorUnderMouse);
translate(event->x(),event->y());
}
}
Tried this - but it is working in reverse.
I suppose you know how to handle events using Qt.
So, to translate (move) your view use the QGraphicsView::translate() method.
EDIT
How to use it:
void CustomGraphicsView::mousePressEvent(QMouseEvent* event)
{
if (e->button() == Qt::MiddleButton)
{
// Store original position.
m_originX = event->x();
m_originY = event->y();
}
}
void CustomGraphicsView::mouseMoveEvent(QMouseEvent* event)
{
if (e->buttons() & Qt::MidButton)
{
QPointF oldp = mapToScene(m_originX, m_originY);
QPointF newP = mapToScene(event->pos());
QPointF translation = newp - oldp;
translate(translation.x(), translation.y());
m_originX = event->x();
m_originY = event->y();
}
}
I have in my UI one QScrollArea with an image, and I want to get some value when I click on the image.
Being more explict, I need to change the brightness of an image, and I will get the value with the mouse. I already see the MouseMoveEvent but I don't know how to use it.
If I get the position of the mouse when I click and drag, I can extract one value to change the bright of my image, that I know. I just don't know how I will get the position.
Does anyone know how I can do this?
Ps.: My QScrollArea was created on Design, so I don't have any code writed by me with the specifications of the QScrollArea.
there is a small correction . when i programmed like this i was getting the movements a liitle jerky . so i tried to modified the code and now working perfect .
heres how i changed
const int deltaX = event->scenePos().x() - m_lastClickPosition.x();
if ( deltaX > 10 )// to the right
{
moveBy(10,0);
m_lastClickPosition = event->scenePos();
}
else if ( deltaX <-10 )
{
moveBy(-10,0);
m_lastClickPosition = event->scenePos();
}
All the information you need is in the QMouseEvent object that is sent to the mouseMoveEvent handler of your widget.
QMouseEvent::buttons()
QMouseEvent::pos()
A simple way to do what you're after is to change the brightness of the image whenever you receive a "mouse movement event" and the QMouseEvent object reports a button down (this means the user is moving the mouse while holding down a button).
void MyWidget::mousePressEvent( QMouseEvent* event )
{
if ( event->button() == Qt::LeftButton )
{
// Keep the clicking position in some private member of type 'QPoint.'
m_lastClickPosition = event->pos();
}
}
void MyWidget::mouseMoveEvent( QMouseEvent* event )
{
// The user is moving the cursor.
// See if the user is pressing down the left mouse button.
if ( event->buttons() & Qt::LeftButton )
{
const int deltaX = event->pos().x() - m_lastClickPosition.x();
if ( deltaX > 0 )
{
// The user is moving the cursor to the RIGHT.
// ...
}
else if ( deltaX < 0 ) // This second IF is necessary in case the movement was all vertical.
{
// The user is moving the cursor to the LEFT.
// ...
}
}
}
I move sprites stored in a formationvector by holding the mousebutton. Problem is: Whenever i move the sprite onto another one, i move both sprites at the same time.
What i want: Moving the sprite1 over the other sprites2 without changing the position of sprite 2 or with other words:
-Testing in a loop if a sprite of a vector is clicked on
-If sprite is clicked on:
Move this sprite around while button is pressed but somehow stop this move while this movement in order to avoid moving more than this one sprite.
Here is my try so far:
while (App.pollEvent(Event))
{
// Window closed
if (Event.type == sf::Event::Closed)
{
return (-1);
}
if (sf::Mouse::isButtonPressed(sf::Mouse::Left))
{
for (size_t k = 0; k < formation.size(); k++)
{
if (isMouseOver(formation[k], App) == true)
{
Mouseposition = sf::Vector2f(sf::Mouse::getPosition(App));
Mouseposition.x = Mouseposition.x - formation[k].getLocalBounds().width / 2;
Mouseposition.y = Mouseposition.y - formation[k].getLocalBounds().height / 2;
formation[k].setPosition(sf::Vector2f(Mouseposition));
Formation_playernames.clear();
Formation_playerinformation.clear();
Formation_Playernames(Font, Formation_playernames, formation, playerlist);
Formation_Playerinformation(Font, Formation_playerinformation, formation, playerlist);
}
}
}
}
The Formation-functions store the correct new positions of the sprites and their colors based on the positions into the formation vector
The problem is the for-loop, i could do it without but that would lead to a much longer code. How could i do it ?
Instead of simply checking whether or not the mouse button is pressed, you should structure your code so you can check exactly when the button is pressed, and when it is released. You can then structure your code such that different presses of the button are distinguished from each other. semi-pseudocode follows
bool button_is_pressed = false;
Sprite* currently_selected_sprite = nullptr;
// main application loop
while (...)
{
...
// other application logic
...
if (!button_is_pressed)
{
if (CheckIfButtonIsPressed())
{
button_is_pressed = true;
// Button was just pressed.
// Select the appropriate sprite by checking
// the mouse coordinates against the positions
// of the sprites.
}
else
{
// Button not being pressed.
// Likely no logic needed here.
}
}
else // button_is_pressed == true
{
if (CheckIfButtonIsPressed())
{
// Button is being held down.
// Implement dragging logic using the
// pointer to the selected sprite.
}
else
{
button_is_pressed = false;
// Button was just released.
// Deselect the sprite.
currently_selected_sprite = nullptr;
}
}
}
Alternatively, you could handle mouse events, which will take care of much of this logic for you. http://sfml-dev.org/documentation/2.0/classsf_1_1Event.php
In a more English like pseudo code, this is what your function is doing:
if the mouse button is currently pressed
move all the sprites which are under the mouse to be centered on the mouse cursor
else
do nothing
This is what I'm suggesting
at the moment the mouse button is pressed down
select the sprite which is under the mouse cursor
at the moment the mouse button is released
deselect the selected sprite
if the mouse button is currently pressed, and a sprite is selected
move the selected sprite to the position of the mouse cursor
I have a code I want to load every time I move my mouse cursor; it draws line to direction of mouse and beyond, and every time it the line gets to certain x coordinate, the line reflects. The problem is that now the program only draws line when I click on the PaintBox.
Here is my code so far:
void __fastcall TForm2::PaintBox1Click(TObject *Sender)
{
Form2->Refresh();
TPoint P;
::GetCursorPos( &P );
P = ScreenToClient( P );
int XX;
int YY;
if (P.x<240)
{
XX=15;
YY= ((445-P.y)*(XX-P.x)/(240-P.x)+P.y);
}
else if(P.x==240)
{
XX=240;YY=-5;
}
else
{
XX=465;
YY= ((445-P.y)*(XX-P.x)/(240-P.x)+P.y);
}
int delta=2*(445-YY);
this->Canvas->MoveTo(240, 445);
this->Canvas->LineTo(XX,YY);
while(0<YY&&YY<480&&YY!=445)
{
XX=abs(480-XX);
YY-=delta;
this->Canvas->LineTo(XX,YY);
}
}
You are trying to paint in an OnClick event handler. That's the wrong place to paint. The only correct place to paint to a VCL paint box is from its OnPaint event handler.
You will need to respond to OnClick though. Make a note of the location of the click and update any state that you need to maintain. Then call Invalidate on the paint box to force a paint cycle.