I have two windows, one at the top, and one at the bottom (and I will be adding a third window later that will be between those two windows). I draw a horizontal line for the bottom window and then I start drawing the top window, and the bottom window gets erased!
The constructor display() is called automatically and than the function displayMessage() is called by my code.
Here is the code for display():
display::display()
{
//initialize window
initscr(); //start curses mode
cbreak(); //Disable line buffering
curs_set(0); //Don't show curser
refresh(); //Now refresh screen
//setup bottom bar
bottomBar = newwin(2, 80, 22, 0); //create new window
whline(bottomBar, '_', 80); //draw line
wrefresh(bottomBar); //refresh
//setup top bar
topBar = newwin(0, 80, 0, 0); //create new window
wattron(topBar, A_UNDERLINE); //text is to be underlined
}
Here is the code for displayMessage():
void display::displayMessage(string message)
{
//do some other necessary stuff
int length = message.length(); //get length of message
wmove(topBar, 0, 0); //move curser back to beginning
//getch();
wrefresh(topBar); //refresh
//getch();
whline(topBar, '_',80); //draw line for bottom
//getch();
wmove(topBar, 0, 40 - length/2 - 1); //move cursor to center text
wprintw(topBar,message.c_str()); //print message
wrefresh(topBar); //refresh
}
In addition here is the code snippets that call those two:
//initialize stuff
pomodoro instance;
while(true) //loop forever, or until user
{
for (int i = 0; i < 3; i++) //loop thru 4 pomodoros
{
//work
instance.Display.displayMessage("**Time to work!**");
instance.playAlarm();
//waitForUser();
//timer(config.workTime);
//break
return 0; //doing development right now
This line is a problem:
topBar = newwin(0, 80, 0, 0); //create new window
because the first parameter is zero. The manual page explains:
If either nlines or ncols is zero, they default to
LINES - begin_y and
COLS - begin_x.
So the zero-parameter makes your windows overlap (a lot).
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I'm trying to create a scribble clone for a uni project.
My lines are basically a lot of dots. If I draw too quick, the line breaks and I have single dots.
Also, I can't figure out how to draw lines ONLY when a mouse button is pressed.
I tried to put mouseMoved into a while loop until mouseButton is released but that didn't seem to work. I ended up in an infinite loop.
Here is my code so far:
while (window.isOpen())
{
while (window.pollEvent(event))
{
int mouseButtonX = event.mouseButton.x;
int mouseButtonY = event.mouseButton.y;
int mouseMoveX = event.mouseMove.x;
int mouseMoveY = event.mouseMove.y;
setBrushSize(5);
brush.setRadius(brushSize);
brush.setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
brush.setFillColor(sf::Color::Transparent);
brush.setOutlineColor(sf::Color::Green);
brush.setOutlineThickness(2);
switch (event.type) {
case (sf::Event::Closed):
window.close();
break;
case (sf::Event::KeyPressed):
if (event.key.control && event.key.code == sf::Keyboard::X) {
cout << "closing";
window.close();
}
if (event.key.code == sf::Keyboard::R) {
cout << "printed";
brushColor = setBrushColor(255, 0, 0);
}
if (event.key.code == sf::Keyboard::G) {
brushColor = setBrushColor(0, 255, 0);
}
if (event.key.code == sf::Keyboard::B) {
brushColor = setBrushColor(0, 0, 255);
}
if (event.key.code == sf::Keyboard::C) {
for (int i = 0; i < points.size(); i++) {
points.clear();
}
it = 0;
}
break;
case(sf::Event::MouseButtonPressed):
points.push_back(point);
points[it].setRadius(brushSize);
points[it].setFillColor(brushColor);
points[it].setPosition(mouseButtonX - brushSize, mouseButtonY - brushSize);
it++;
cout << "drawPoint: Pressed X = " << mouseButtonX << " Y = " << mouseButtonY << endl;
break;
case(sf::Event::MouseMoved):
points.push_back(point);
points[it].setRadius(brushSize);
points[it].setFillColor(brushColor);
points[it].setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
it++;
cout << "drawPoint: Moved X = " << mouseMoveX << " Y = " << mouseMoveY << endl;
break;
}
}
window.clear(sf::Color(255, 247, 204));
window.draw(SkechyT);
window.draw(close);
window.draw(brush);
window.draw(color);
window.draw(clear);
for (int i = 0; i < points.size(); i++) {
window.draw(points[i]);
}
//window.draw(point);
window.display();
}
}
int getBrushSize() {
return brushSize;
}
void setBrushSize(int num) {
brushSize = num;
}
sf::Color setBrushColor(int r, int g, int b) {
return sf::Color(r, g, b);
}
~Visualizer();
};
While you can modify a sf::VertexArray on the fly (basically building a vector drawing app), you can also use a sf::RenderTexture as an actual drawing canvas.
Considering you tried drawing lots of small points, I'd assume you're aiming for the latter. What's important here is the fact that you don't necessarily have to clear render textures between drawing calls and can therefore preserve whatever has been drawn before.
Combined with the original goal – drawing – this becomes very easy.
All you have to do is draw the changes (e.g. when moving the cursor), finalize the render texture (by calling display()), and then presenting it using any drawable (like sf::Sprite.
I've quickly scribbled together the following example, which should show the concept rather well (and you won't run into an endless loop other than the actual main loop):
#include <SFML/Graphics.hpp>
#include <vector>
int main(int argc, char **argv) {
sf::RenderWindow window(sf::VideoMode(800, 600), L"SFML Drawing – C to clear, PageUp/PageDown to pick colors", sf::Style::Default);
// Set a specific frame rate, since we don't want to
// worry about vsync or the time between drawing iterations
window.setVerticalSyncEnabled(false);
window.setFramerateLimit(100);
// First we'll use a canvas to basically store our image
sf::RenderTexture canvas;
canvas.create(800, 600);
canvas.clear(sf::Color::White);
// Next we'll need a sprite as a helper to draw our canvas
sf::Sprite sprite;
sprite.setTexture(canvas.getTexture(), true);
// Define some colors to use
// These are all with very low alpha so we
// can (over-)draw based on how fast we move the cursor
const std::vector<sf::Color> colors = {
sf::Color(255, 0, 0, 8),
sf::Color(255, 255, 0, 8),
sf::Color(0, 255, 0, 8),
sf::Color(0, 255, 255, 8),
sf::Color(0, 0, 255, 8),
sf::Color(255, 0, 255, 8)
};
// We'll need something to actually draw
// For simplicity, I'm just drawing a circle shape
// but you could also draw a line, rectangle, or something more complex
const float brush_size = 25;
sf::CircleShape brush(brush_size, 24);
brush.setOrigin(brush_size, brush_size); // Center on the circle's center
sf::Vector2f lastPos;
bool isDrawing = false;
unsigned int color = 0;
// Apply some default color
brush.setFillColor(colors[color]);
while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
switch (event.type) {
case sf::Event::Closed:
window.close();
break;
case sf::Event::KeyPressed:
switch (event.key.code) {
case sf::Keyboard::C:
// Clear our canvas
canvas.clear(sf::Color::White);
canvas.display();
break;
case sf::Keyboard::PageUp:
// Get next color
color = (color + 1) % colors.size();
// Apply it
brush.setFillColor(colors[color]);
break;
case sf::Keyboard::PageDown:
// Get previous color
color = (color - 1) % colors.size();
// Apply it
brush.setFillColor(colors[color]);
break;
}
break;
case sf::Event::Resized:
{
// Window got resized, update the view to the new size
sf::View view(window.getView());
const sf::Vector2f size(window.getSize().x, window.getSize().y);
view.setSize(size); // Set the size
view.setCenter(size / 2.f); // Set the center, moving our drawing to the top left
window.setView(view); // Apply the view
break;
}
case sf::Event::MouseButtonPressed:
// Only care for the left button
if (event.mouseButton.button == sf::Mouse::Left) {
isDrawing = true;
// Store the cursor position relative to the canvas
lastPos = window.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});
// Now let's draw our brush once, so we can
// draw dots without actually draging the mouse
brush.setPosition(lastPos);
// Draw our "brush"
canvas.draw(brush);
// Finalize the texture
canvas.display();
}
break;
case sf::Event::MouseButtonReleased:
// Only care for the left button
if (event.mouseButton.button == sf::Mouse::Left)
isDrawing = false;
break;
case sf::Event::MouseMoved:
if (isDrawing)
{
// Calculate the cursor position relative to the canvas
const sf::Vector2f newPos(window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y)));
// I'm only using the new position here
// but you could also use `lastPos` to draw a
// line or rectangle instead
brush.setPosition(newPos);
// Draw our "brush"
canvas.draw(brush);
// Finalize the texture
canvas.display();
break;
}
}
}
// Clear the window
window.clear(sf::Color(64, 64, 64));
// Draw our canvas
window.draw(sprite);
// Show the window
window.display();
}
return 0;
}
Once running, you can start drawing using the left mouse button. C will clear the canvas and Page Up and Page Down allow you to pick a different color:
Edit: And just to mention it, in the example above, rather than drawing a circle, you can just draw a sf::VertexArray with sf::Lines and two vertices: lastPos and newPos. This way you'll always draw a continuous line. (But you'd obviously have to save/update lastPos with the value of newPos once you're done.)
I am drawing ruler using the sample application given in the link.
http://www.ucancode.net/Visual_C_Source_Code/MFC-MDI-SDI-Example-create-ruler-scrollview-splitter.htm
On moving cursor they are drawing black line marker. I want to draw red color line like in microsoft paint application.
In the sample they are using below code for drawing line.
What needs to be done to draw red color line.
void CRulerView::DrawCursorPos(CPoint NewPos)
{
if (((m_rulerType == RT_HORIZONTAL) && (NewPos.x > m_DocSize.cx*m_fZoomFactor)) ||
((m_rulerType == RT_VERTICAL) && ((NewPos.y) > m_DocSize.cy*m_fZoomFactor)))
return;
CDC* pDC = GetDC();
// set the map mode right
int oldMapMode = pDC->SetMapMode(MM_TEXT);
//HBRUSH hBr=CreateSolidBrush(RGB(255,0,0));
//pDC->SelectObject(hBr);
//CBrush* pTempBrush = NULL;
// pTempBrush = (CBrush*)pDC->SelectObject(&hBr);
CRect clientRect;
GetClientRect(&clientRect);
if (m_rulerType==RT_HORIZONTAL)
{
// erase the previous position
pDC->PatBlt(m_lastPos.x, clientRect.top, 1, clientRect.bottom, DSTINVERT);
// draw the new position
m_lastPos.x = NewPos.x;
pDC->PatBlt(m_lastPos.x, clientRect.top, 1, clientRect.bottom, DSTINVERT);
}
else // (m_rulerType==RT_VERTICAL)
{
// erase the previous position
pDC->PatBlt(clientRect.left, m_lastPos.y, clientRect.right, 1, DSTINVERT);
// draw the new position
m_lastPos.y = NewPos.y;
pDC->PatBlt(clientRect.left, m_lastPos.y, clientRect.right, 1, DSTINVERT);
}
//pDC->SelectObject(&pTempBrush);
pDC->SetMapMode(oldMapMode);
ReleaseDC(pDC);
}
im trying to show two different animations made with two functions, one render and two threads.
Im getting different kind of error each time i run the code.
Such as: segmentation default in the refresh function (line SDL_RenderPresent(w1.renderer);) and other strange errors too. Everytime is different.
I know its about using the render in both different threads. But i dont know how to solve this problem.
When i run with just one of the threads everything its ok. But not with the two of them.
I just want to show different graphics playing around the window. (always using sdl2).
Here is my code:
window.h:
class Window
{
public:
SDL_Window *window1;
int background,windowWidth,windowHeight,windowXcoord,windowYcoord;
SDL_Renderer * renderer;
SDL_Renderer * renderer2;
Window();
};
void refresh();
extern Window w1;
window.cpp:
Window w1;
Window::Window()
{
window1=nullptr;
background = 0xffffff;
windowWidth=700; windowHeight=500;
windowXcoord = 650; windowYcoord = 0;
this->window1 =
SDL_CreateWindow("Window",windowXcoord,windowYcoord,
windowWidth,windowHeight, SDL_WINDOW_SHOWN);
this->renderer = SDL_CreateRenderer( this->window1, -1 ,
SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor( this->renderer, 255, 255, 255, 255 );
SDL_RenderClear( this->renderer );
SDL_RenderPresent(this->renderer);
}
// this function is called everytime an object or function want to "refresh" the window.
void refresh(){
// clearing the window
SDL_SetRenderDrawColor( w1.renderer, 255, 255, 255,0 );
SDL_RenderClear( w1.renderer );
// r1, the first Rects object to animate.
SDL_SetRenderDrawColor( w1.renderer,255,0,0,255);
SDL_RenderFillRect( w1.renderer, &r1.rect );
// r2, the second Rects.
SDL_SetRenderDrawColor( w1.renderer,255,0,255,255);
SDL_RenderFillRect( w1.renderer, &r2.rect );
SDL_RenderPresent(w1.renderer);
}
rects.h:
class Rects
{
public:
SDL_Rect rect;
Rects();
};
extern Rects r1, r2;
void moveR1();
void moveR2();
rects.cpp:
Rects::Rects()
{ }
Rects r1,r2;
// moveR1 and moveR2, (just some dumm animations-example)
void moveR1(){
r1.rect.x=400; r1.rect.y=100;
r1.rect.w =40; r1.rect.h =10;
SDL_SetRenderDrawColor( w1.renderer,255,0,0,255);
SDL_RenderFillRect( w1.renderer, &r1.rect );
{
for (int u = 1; u<=5;u++){
r1.rect.x=200; r1.rect.y=100;
r1.rect.w =50; r1.rect.h =50;
refresh();
for (int i = 1; i <=200; i++){
r1.rect.x-=1;
usleep (7000);
refresh();
}
}
}
}
void moveR2(){
r2.rect.x=200; r2.rect.y=100;
r2.rect.w =40; r2.rect.h =10;
SDL_SetRenderDrawColor( w1.renderer,255,255,0,255);
SDL_RenderFillRect( w1.renderer, &r2.rect );
{
for (int u = 1; u<=5;u++){
check
r2.rect.x=200; r2.rect.y=100;
r2.rect.w =50; r2.rect.h =50;
refresh();
for (int i = 1; i <=200; i++){
r2.rect.x+=1; r2.rect.y+=1;
usleep (7000);
refresh();
}
}
}
}
and the main:
int main()
{
thread t1(moveR1);
t1.detach();
thread t2(moveR2);
t2.detach();
// sleep instead of showing a loop.
sleep (10);
return 0;
}
any polite help is welcome, im here to learn.
When i run with just one of the threads everything its ok. But not with the two of them.
According to the documentation for 2D accelerated rendering (also known as SDL_render.h, in other terms the place where SDL_RenderPresent lives):
This API is not designed to be used from multiple threads, see SDL bug #1995 for details.
You won't be able to do that any time soon. By looking at the description of the error, it looks like an UB and the link to the bug gives you all the details probably.
I just want to show different graphics playing around the window.
You don't need to use two threads to do that.
You can just update positions, animations and whatever is needed for your graphics and show them from the same thread. Nothing prevents you from calling the same function (as an example SDL_RenderCopy) more than once before to invoke SDL_RenderPresent.
If you needed a thread per graphic, what about a game with thousands of polygons on video?
// thanks to skypjack, i am able to solve the problem
// HOW TO PRESENT TWO (OR MORE) GRAPHICS WITH SDL_RENDERER WITHOUT USING THREADS.
// The two rectangle animation are just and example.
// It could be whatever we want to show.
// In this case, just two rectangles moving around.
#include <unistd.h>
#include <SDL.h>
using namespace std;
SDL_Window *window1;
int background, windowWidth, windowHeight,windowXcoord,
windowYcoord;
SDL_Rect rectangle1;
SDL_Rect rectangle2;
SDL_Renderer *renderer;
int sequence1;
int sequence2;
void moveRectangle1(), moveRectangle2();
int main()
{
window1=nullptr;
background = 0xffffff;
windowWidth=700; windowHeight=500;
windowXcoord = 650; windowYcoord = 0;
window1 = SDL_CreateWindow("Main
Window",windowXcoord,windowYcoord, windowWidth,windowHeight,
SDL_WINDOW_SHOWN);
renderer = SDL_CreateRenderer( window1, -1 ,
SDL_RENDERER_ACCELERATED);
SDL_SetRenderDrawColor( renderer, 255, 255, 255, 255 );
SDL_RenderClear( renderer );
SDL_RenderPresent(renderer);
rectangle1.x = 100; rectangle1.y = 100; rectangle1.h = 40;
rectangle1.w = 40;
rectangle2.x = 100; rectangle2.y = 100; rectangle2.h = 40;
rectangle2.w = 40;
for (int i = 1;i<500;i++){
SDL_SetRenderDrawColor( renderer, 255, 255, 255,0 );
SDL_RenderClear( renderer );
// chequear return (cerrar programa)
moveRectangle1();
moveRectangle2();
SDL_RenderPresent(renderer);
usleep (12000);
}
return 0;
}
void moveRectangle1(){
sequence1++;
if (sequence1 <= 50){ rectangle1.x++; }
else if (sequence1 <= 100){ rectangle1.x--; }
else { sequence1 = 0; }
SDL_SetRenderDrawColor(renderer,255,0,0,255);
SDL_RenderFillRect(renderer, &rectangle1 );
}
void moveRectangle2(){
sequence2++;
if (sequence2 <= 100){ rectangle2.y++; }
else if (sequence2 <= 200){ rectangle2.y--; }
else { sequence2 = 0; }
SDL_SetRenderDrawColor(renderer,0,200,0,255);
SDL_RenderFillRect( renderer, &rectangle2 );
}
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);
I'm trying to run this code through Eclipse. It has no errors when compiling and opens up Terminal (as I set it to) when it runs, but nothing shows up in the Terminal even though (supposedly) I have coded it to display a box. Could anyone let me know what I need to do so that it displays properly?
Thanks
#include <iostream>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
void set_difficulty(int level,int &v);
void SetMenuBox(WINDOW*&);
int main(){
int speed = 0;
chtype a=219;
initscr(); //initialize screen
WINDOW *win = newwin(20,40,15,20); //create new window (row,col,x,y) where (x,y) is top left corner
wrefresh(stdscr); //refresh standard screen
start_color(); //enable color changes
init_pair(1,COLOR_RED,COLOR_BLACK); //create color pair of red text with black outline
init_pair(2,COLOR_GREEN,COLOR_BLACK);
attron(COLOR_PAIR(1)); //use the color pair
wattron(win,COLOR_PAIR(1));
wrefresh(win);
wborder(stdscr,0,0,0,0,0,0,0,0); //create border around win using lines
wborder(win,a,a,a,a,a,a,a,a); //create border around standard window
wrefresh(stdscr);
wrefresh(win);
wmove(win,2,18); //move cursor
wprintw(win,"MENU"); //print "MENU" at cursor
wmove(win,5,2);
wprintw(win,"Select Difficulty:");
wmove(win,7,2);
wprintw(win,"1==Easy");
wmove(win,9,2);
wprintw(win,"2==Medium");
wmove(win,11,2);
wprintw(win,"3==Hard");
wmove(win,13,2);
wprintw(win,"0==EXIT");
wmove(win,18,19);
wrefresh(win); //the character typed will be green not blue
int d=wgetch(win); //get character from win, d is the ascii number
sleep(500); //pause for 1000 ms
wmove(win,28,25);
while(d<48||d>51){ //keeps getting character until an allowable
wborder(win,32,32,32,32,32,32,32,32); //character is selected
mvwdelch(win,18,19);
wborder(win,a,a,a,a,a,a,a,a);
wmove(win,18,19);
wrefresh(win);
d = wgetch(win);
sleep(500);
}
if(d==48)
return 0;
else if(d>48&&d<=51){
set_difficulty(d,speed);
}
wrefresh(win);
sleep(1000);
wclear(win);
SetMenuBox(win);
wrefresh(win);
wmove(win,15,18);
wprintw(win,"%d",speed);
wrefresh(win);
sleep(1000);
//endwin(); //close window
return 0;
}
void set_difficulty(int level,int &v){
switch (level){
case 49:
v = 2500;
break;
case 50:
v = 1750;
break;
case 51:
v = 1250;
break;
}
}
void SetMenuBox(WINDOW *&w){
chtype a = 219;
delwin(w);
wrefresh(stdscr);
w = newwin(30,40,15,20);
wrefresh(stdscr);
wrefresh(w);
init_pair(1,COLOR_RED,COLOR_BLACK); //create color pair of red text with blue outline
attron(COLOR_PAIR(1)); //use the color pair
wattron(w,COLOR_PAIR(1));
wrefresh(w);
wborder(w,a,a,a,a,a,a,a,a);
wrefresh(w);
}