I was making a basic paint/draw program in processing where the Left click would draw a point and a Right click would draw a background colored rectangle to "erase". The thing is that when I start erasing it wont let me go back to drawing. Also i would like to make the dots draw faster so it looks more like a line rather than a dotted line. Thanks!
Here is the code:
void setup() {
size(600, 600);
background(#C4C4C4);
}
void draw() {
frameRate(60);
if (mouseButton == LEFT) {
fill(#030303);
point(mouseX, mouseY);
}
else if(mouseButton == RIGHT){
fill(#C4C4C4);
noStroke();
rect(mouseX-15, mouseY-15, 30, 30);
}
}
Your main problem is that you call noStroke() when the user presses the right button, but you never set the stroke back when the user presses the left button. The point() function uses the stroke color, not the fill color, so you have to reset it. This works:
void setup() {
size(400, 400);
background(#C4C4C4);
}
void draw() {
if (mouseButton == LEFT) {
stroke(#030303);
point(mouseX, mouseY);
}
else if(mouseButton == RIGHT){
fill(#C4C4C4);
noStroke();
rect(mouseX-15, mouseY-15, 30, 30);
}
}
As for drawing lines instead of a point, you can use the pmouseX and pmouseY variables (which hold the previous position of the mouse) to draw a line. Specifically, change this:
point(mouseX, mouseY);
To this:
line(pmouseX, pmouseY, mouseX, mouseY);
Related
When I position a sprite at 0, 0 (top left corner of the screen) it doesn't show. It's off screen by a few pixels. Here is a sample of my code.
Sprite s;
Texture t;
t.loadFromFile("Tiles.png");
t.setSmooth(false);
s.setTexture(t);
s.setTextureRect(IntRect(0, 0, 16, 16));
s.setPosition(0, 0);
window.draw(s);
window.display();
If I add
Style::None
to my RenderWindow, then the sprite is positioned properly at the top left of the screen.
Is there a way to position sprites ignoring the windows title bar? Or another way to fix this issue? The only way I can seem to get the sprite positioned correctly is if I guess how many pixels off it is and manually add an offset to the sprites position, but this is a very bad way of doing it and I can't get it positioned perfectly. If I set the position to (11, 64), the sprite is at about the top left of the screen.
Edit: Here is a full example piece of code I used to recreate the issue:
#include <SFML/Graphics.hpp>
using namespace sf;
const int WIDTH = 1000;
const int HEIGHT = 1000;
int main()
{
RenderWindow window(VideoMode(WIDTH, HEIGHT), "Window", Style::Titlebar | Style::Close);
RectangleShape square(Vector2f(100.f, 100.f));
square.setFillColor(Color::Red);
square.setPosition(0, 0);
while (window.isOpen())
{
Event windowEvent;
while (window.pollEvent(windowEvent))
{
if (windowEvent.type == Event::Closed)
{
window.close();
}
}
window.clear(Color::White);
window.draw(square);
window.display();
}
return 0;
}
When I run it, this is the result I get. https://i.imgur.com/bIOnb4L.png
Since posting this issue, I've realized that the problem is that when the title bar is enabled, it takes up space on my window, (0, 0) is behind the title bar. I still don't know how to fix it, though.
I'm working on a project where I have to do an image editor similar to Paint. I would like to open up an image, zoom in/zoom out if necessary, and then draw on it.
For that, I used Image Viewer and Scribble examples, the only thing different that I added was a QLabel subclass that is supposed to draw lines and other forms with the mouse press/mouse release events. The problem is with the overriden paintEvent.
void imLabel::paintEvent(QPaintEvent *event){
if(tipo != ""){ //draw mode
QPainter painter(this);
QRect dirtyRect = event->rect();
painter.drawImage(dirtyRect,image,dirtyRect);
}
else QLabel::paintEvent(event);
}
I am able to zoom in normally in the beginning, but when I start drawing the image comes back to its original size, while the rest of the label that is not occupied by the image is completely white, because it kept the zoomed in size.
Is there a way that I can keep the image zoomed in while I draw, just like in Paint?
UPDATE
Here's the code of the draw function, maybe it'll help
void imLabel::draw(const QPoint &endPoint){
QPainter painter(&image);
painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
if(tipo == "maoLivre" || tipo == "reta") //draw line or free hand
painter.drawLine(startPoint, endPoint);
else{
int x = startPoint.x(), y = startPoint.y(),
largura = endPoint.x()- startPoint.x(),
altura = endPoint.y() - startPoint.y();
if(tipo == "retangulo") //draw rectangle
painter.fillRect(x,y,largura,altura,Qt::green);
else if(tipo == "circulo"){ //draw circle
painter.setBrush(Qt::green);
painter.drawEllipse(startPoint,altura,altura);
}
}
modified = true;
update();
startPoint = endPoint;
}
Well, I've been watching a tutorial on how to use SFML. I'm currently learning to move a sprite in the screen. Before adding window.clear(); every time I moved the sprite it left like a trail, like if the sprite was a brush. Then the tutorial man said to add window.clear BEFORE window.draw(player);
Could you please explain the logic behind that? Like, the window gets cleared, then draws the character and the displays it. Here is the code:
#include <SFML/Graphics.hpp>
#include <iostream>
int main() {
sf::RenderWindow window(sf::VideoMode(1920, 1080), "Screen", sf::Style::Default);
sf::RectangleShape player(sf::Vector2f(100.0f, 100.0f));
player.setFillColor(sf::Color::Green);
//run as long as the window is open
while (window.isOpen()) {
// check all the window's events that were triggered since the last iteration of the loop
sf::Event evnt;
while (window.pollEvent(evnt)) {
switch (evnt.type) {
case sf::Event::Closed:
window.close();
break;
case sf::Event::Resized:
printf("New window width: %i New window height: %i\n", evnt.size.width, evnt.size.height);
break;
case sf::Event::TextEntered:
if (evnt.text.unicode < 128) {
printf("%c", evnt.text.unicode);
}
}
// "close requested" event: we close the window
if (evnt.type == sf::Event::Closed)
window.close();
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W)){
player.move(0.0f, -0.1f);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A)) {
player.move(-0.1f, 0.0f);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S)) {
player.move(0.0f, 0.1f);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D)) {
player.move(0.1f, 0.0f);
}
window.clear();
window.draw(player);
window.display();
}
return 0;
}
The logic behind sf::RenderWindow::clear() is actually quite simple. The reason you see a trail behind the sprite without clear is because you redraw the sprite again without getting rid of the old one. Clearing the screen gets rid of anything that was already on the screen, so you end up with a blank canvas to redraw everything on in its updated position. The character, which is your sprite, isn't actually moving, it is constantly getting redrawn in a new position on the window.
I'm trying to draw multiple line segments with my mouse in my OpenGL and C++ program. Right now I can draw one, and once I start drawing another one, the previous one disappears.
Below is my code that is relevant to the mouse drawing. Any suggestions on how I can draw multiple lines?
LineSegment seg;
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { // if left button is clicked, that is the start point
seg.x1 = seg.x2 = x;
seg.y1 = seg.y2 = y;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) { // once they lift the mouse, thats the finish point
seg.x2 = x;
seg.y2 = y;
}
}
void motion(int x, int y) {
seg.x2 = x;
seg.y2 = y;
glutPostRedisplay(); // refresh the screen showing the motion of the line
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT); // clear the screen
glBegin(GL_LINES); // draw lines
glVertex2f(seg.x1, seg.y1);
glVertex2f(seg.x2, seg.y2);
glEnd();
glutSwapBuffers();
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT); // clear the screen
glBegin(GL_LINES); // draw lines
glVertex2f(seg.x1, seg.y1);
glVertex2f(seg.x2, seg.y2);
glEnd();
glutSwapBuffers();
}
You need to save in a data structure the previous line segments and add to it whenever you click with the mouse. Then the drawloop needs to iterate through that data structure and draw each of the saved line segments.
std::vector<LineSegment> segmentvector;
//Each time you release the mouse button, add the current line segment to this vector
/*...*/
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
for(const LineSegment & seg : segmentvector) {
glVertex2f(seg.x1, seg.y1);
glVertex2f(seg.x2, seg.y2);
}
glVertex2f(currseg.x1, currseg.y1);
glVertex2f(currseg.x2, currseg.y2);
glEnd();
I would also STRONGLY ADVISE that you not use Fixed-Function-Pipeline functions when learning OpenGL. There are lots of tutorials online for learning modern OpenGL.
You need to set up some logic to save the state of the lines you have already drawn. Currently, you never start drawing another line, you just reset the start position of the current line.
Here is a possible solution for what you're looking for:
std::vector<LineSegment> segs;
LineSegment currentSeg;
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
LineSegment newSeg; // Make a new segment
newSeg.x1 = newSeg.x2 = x;
newSeg.y1 = newSeg.y2 = y;
segs.insert(newSeg); // Insert segment into segment vector
currentSeg = newSeg;
}
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
currentSeg.x2 = x;
currentSeg.y2 = y;
}
}
void motion(int x, int y) {
currentSeg.x2 = x;
currentSeg.y2 = y;
glutPostRedisplay();
}
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_LINES);
// Iterate through segments in your vector and draw each
for(const auto& seg : segs) {
glVertex2f(seg.x1, seg.y1);
glVertex2f(seg.x2, seg.y2);
}
glEnd();
glutSwapBuffers();
}
I'm trying to make a Paint application in C++ with Qt. Everytime I click or click & drag the mouse, the program will draw something on a pixmap. After that, it updates the window calling paintEvent(), which will draw the pixmap onto the window.
void QPaintArea::mousePressEvent(QMouseEvent *event){
startpoint = event->pos();
drawPoint(startpoint);
is_pressed = true;
}
void QPaintArea::mouseReleaseEvent(QMouseEvent *event){
is_pressed = false;
}
void QPaintArea::mouseMoveEvent(QMouseEvent *event){
if(is_pressed == true){
endpoint = event->pos();
drawLine(startpoint, endpoint);
startpoint = endpoint;
}
else{
return;
}
}
void QPaintArea::paintEvent(QPaintEvent *event){
QDesktopWidget *desktop = QApplication::desktop();
int x = (desktop->width() - 800) / 2;
int y = (desktop->height() - 600) / 2;
QPainter painter(this);
QRect target(QPoint(x, y - 35), QSize(800, 600));
QRect dirtyrect(QPoint(0,0), QSize(800, 600));
painter.drawPixmap(target, *pixmap, dirtyrect);
}
The problem is that, the program is not printing the pixmap onto the window as expected. For example, I press the mouse at x: 17, y: 82 trying to draw something. The program will print what I drew but at an offset location, like x + 20, y.
Maybe I don't fully understand how QRect or drawPixmap works, but the pixmap is 800x600. "dirtyrect" is supposed to save the entire pixmap (starting a x: 0, y: 0, and the size 800x600).
drawPixmap(target, pixmap, source) paints on target rect of painter area (QPaintArea in this case) source part of pixmap. So you paint whole pixmap (0,0,800,600) at some (x,y-35,800,600) rect of QPaintArea. If you want to paint whole pixmap on whole QPaintArea just use drawPixmap(QPoint(0,0), *pixmap).
// EDIT
But if you expected, that pixmap will be painted with some offset from QPaintArea top left corner, then your calculations are wrong, and if you wont explain what did you want to achieve we won't be able to help you. Explain us your calculations of x,y (and magic -35 for y), and maybe we will be able to figure something out
// EDIT
You don't have to use window offsets like -35 if you're painting on widget. 0,0 of the widget is not top left corner of window frame, but of widget contents. How do you expect it to behave on other platforms?
If you want to paint it in the middle of your window simply use:
void QPaintArea::paintEvent(QPaintEvent *event){
QPoint middle = geometry.center();
int x = middle.x() - 800/2; // probably best would be pixmap->width()/2
int y = middle.y() - 600/2; // probably best would be pixmap->height()/2
QPainter painter(this);
painter.drawPixmap(QPoint(x,y), *pixmap);
}