SDL, knappar (C++)

Avdelningen för programmering, nätverk samt alternativa OS.
Post Reply
User avatar
jb
Posts: 1076
Joined: 2002-08-08 3:39:12
Location: Karlshamn
Contact:

SDL, knappar (C++)

Post by jb »

Jag håller på att lära mig C++ och SDL, så jag kodar en chipdisk (dvs ett program som spelar upp medföljande chipmusik, t.ex. http://www.pouet.net/prod.php?which=17356). Har fått lite problem med min klass som skapar knappar.. Bara den första knappen jag gör i programmet vill funka att klicka på, de andra händer det inget av.

Eftersom att jag lär mig så får ni gärna klaga på koden också, men ni får också tänka på att allt inte är klart. Kan hända att jag har inkluderat iostream någonstans och glömt att ta bort det också. Vore fint om någon kunde hjälpa mig, har inte en aning om vad jag gör fel :)

button.h:

Code: Select all

#ifndef BUTTON_H
#define BUTTON_H

#include "image.h"
#include "event.h"

class Button {
	public:
		Button(const char *file, int x, int y, void (*function)());
		void update(SDL_Surface *screen);
	private:
		void (*clickFunction)();
		SDL_Rect box;
		bool clicked;
		Image image;
		Event event;
};

#endif
button.cpp (antagligen den det är fel i):

Code: Select all

#include "button.h"
#include <iostream>

Button::Button(const char *file, int x, int y, void (*function)()) {
	clicked = false;
	image.load(file);
	box.w = image.getWidth();
	box.h = image.getHeight();
	box.x = x;
	box.y = y;
	clickFunction = function;
}

void Button::update(SDL_Surface *screen) {
	image.show(screen, box.x, box.y);
	clicked = false;
	event.update();
	
	if (event.current == LEFTDOWN) {
		if ((event.getMouseX() > box.x) && (event.getMouseX() < box.x+box.w)
			&& (event.getMouseY() > box.y) && (event.getMouseY() < box.y+box.h)) {
			clicked = true;
		}
	}
	
	if (clicked)
		clickFunction();
}
image.h:

Code: Select all

#ifndef IMAGE_H
#define IMAGE_H

#include <SDL_image/SDL_image.h>
#include <iostream>

class Image {
	public:
		void load(const char *file);
		int getWidth() { return image->w; }
		int getHeight() { return image->h; }
		void show(SDL_Surface *surface, int x, int y);
	private:
		SDL_Surface *image;
		SDL_Rect dest;
};

#endif
image.cpp:

Code: Select all

#include "image.h"

void Image::load(const char *file) {
	image = IMG_Load(file);
	if (!image) {
		std::cout << "Error: " << IMG_GetError() << std::endl;
		std::exit(1);
	}
}

void Image::show(SDL_Surface *surface, int x, int y) {
	dest.x = x;
	dest.y = y;
	SDL_BlitSurface(image, NULL, surface, &dest);
}
event.h:

Code: Select all

#ifndef EVENT_H
#define EVENT_H

#define LEFTDOWN 1
#define LEFTUP 2
#define RIGHTDOWN 3
#define RIGHTUP 4
#define KEYDOWN 5

#include "SDL.h"
#include <iostream>

class Event {
	public:
		Event();
		void update();
		int current;
		SDLKey getKey() { return kbInput; }
		int getMouseX() { return mousex; }
		int getMouseY() { return mousey; }
	private:
		SDL_Event event;
		int mousex, mousey;
		SDLKey kbInput;
		SDLMod modInput;
		Uint16 unicode;
};

#endif
event.cpp:

Code: Select all

//den här tycker jag att är lite konstig, men vafan ;D 

#include "event.h"

Event::Event() {
	current = 0;
	kbInput = SDLK_UNKNOWN;
}

void Event::update() {
	current = 0;
	while (SDL_PollEvent(&event)) {
		switch (event.type) {
			case SDL_MOUSEMOTION:
				mousex = event.motion.x;
				mousey = event.motion.y;
				break;
			case SDL_MOUSEBUTTONDOWN:
				if (event.button.button == SDL_BUTTON_LEFT)
					current = LEFTDOWN;
				else if (event.button.button == SDL_BUTTON_RIGHT)
					current = RIGHTDOWN;
				break;
			case SDL_MOUSEBUTTONUP:
				if (event.button.button == SDL_BUTTON_LEFT)
					current = LEFTUP;
				else if (event.button.button == SDL_BUTTON_RIGHT)
					current = RIGHTUP;
				break;
			case SDL_KEYDOWN:
				current = KEYDOWN;
				kbInput = event.key.keysym.sym;
				modInput = event.key.keysym.mod;
				unicode = event.key.keysym.unicode;
				break;
			case SDL_QUIT:
				SDL_Quit();
				std::exit(0);
				break;
		}
	}
}
Ny låt ---> Jallabert - KRS3
User avatar
straver
Posts: 485
Joined: 2002-03-09 13:51:28
Location: Malmö
Contact:

Post by straver »

Vore mycket lättare att felsöka om du ladda upp filer man kan kompilera å köra.

Den här koden täcker ju inte all kod. T.ex finns inte koden för uppdateringen för knapparna med. Annars kan du ju kolla att
din event klass verkligen ger tillbaks det du vill och inte alltid ger tillbaks LEFTUP istället för LEFTDOWN eller liknande.
User avatar
jb
Posts: 1076
Joined: 2002-08-08 3:39:12
Location: Karlshamn
Contact:

Post by jb »

straver wrote:Vore mycket lättare att felsöka om du ladda upp filer man kan kompilera å köra.
Ok, ska fixa någon gång ikväll/inatt, har inte tid nu.
straver wrote:Den här koden täcker ju inte all kod. T.ex finns inte koden för uppdateringen för knapparna med.
Det finns den väl visst?
straver wrote:Annars kan du ju kolla att
din event klass verkligen ger tillbaks det du vill och inte alltid ger tillbaks LEFTUP istället för LEFTDOWN eller liknande.
Eventklassen verkar funka som den ska. Felet verkar vara att den bara kollar om jag klickar på första knappen jag kör update() på, men varför vet jag inte. Eventklassen vet att jag klickar och var jag klickar, men buttonklassen vill ändå bara att den första jag kör update() på ska funka :(
Ny låt ---> Jallabert - KRS3
User avatar
jb
Posts: 1076
Joined: 2002-08-08 3:39:12
Location: Karlshamn
Contact:

Post by jb »

Ok, här kommer testkod.

main.cpp:

Code: Select all

#include <iostream>
#include "image.h"
#include "button.h"
#include "event.h"
#include "SDL.h"

void test1() {
	std::cout << "test1" << std::endl;
}

void test2() {
	std::cout << "test2" << std::endl;
}

void test3() {
	std::cout << "test3" << std::endl;
}

int main(int argc, char *argv[]) {
	Image bg;
	bg.load("bg.png");
	
	Event event;
	SDL_Surface *screen;

	Button prev = Button("prev.png", 5, 65, test1);
	Button stop = Button("stop.png", 20, 65, test2);
	Button pause = Button("pause.png", 35, 65, test3);
	
	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
		std::cout << SDL_GetError() << std::endl;
	}
	
	screen = SDL_SetVideoMode(bg.getWidth(), bg.getHeight(), 24, SDL_HWSURFACE|SDL_DOUBLEBUF);
	if (screen == NULL) {
		std::cout << SDL_GetError() << std::endl;
	}
		
	while (1) {
		prev.update(screen);
		stop.update(screen);
		pause.update(screen);
		event.update();
		bg.show(screen, 0, 0);
		SDL_Flip(screen);
	}
}
Behövs ett par jättefina bilder också, de finns på http://jallabert.tjc.se:81/bilder/
Ny låt ---> Jallabert - KRS3
User avatar
straver
Posts: 485
Joined: 2002-03-09 13:51:28
Location: Malmö
Contact:

Post by straver »

Okej,

Problemet var att varje knapp körde sin egen event-loop. Vilket får effekten att den första knappen rensar ut alla events.

En lösning som inte kräver så stora kodförändringar är att göra variablerna i Event static och bara köra bara köra update en gång i main loop:en.

Code: Select all

#ifndef EVENT_H 
#define EVENT_H 
 
#define LEFTDOWN 1 
#define LEFTUP 2 
#define RIGHTDOWN 3 
#define RIGHTUP 4 
#define KEYDOWN 5 
 
#include <SDL/SDL.h> 
#include <iostream> 
 
class Event { 
   public: 
      Event(); 
      void update(); 
      static int current; 
      SDLKey getKey() { return kbInput; } 
      int getMouseX() { return mousex; } 
      int getMouseY() { return mousey; } 
   private: 
      static SDL_Event event; 
      static int mousex, mousey; 
      static SDLKey kbInput; 
      static SDLMod modInput; 
      static Uint16 unicode; 
}; 
 
#endif
SDL_MOUSEBUTTONUP kan komma i samma event loop som SDLMOUSEBUTTONDOWN

Code: Select all

#include "event.h" 

int Event::mousex;
int Event::mousey;
int Event::current;
SDL_Event Event::event;
SDLKey Event::kbInput;
SDLMod Event::modInput;
Uint16 Event::unicode;
 
Event::Event() { 
   current = 0; 
   kbInput = SDLK_UNKNOWN; 
} 
 
void Event::update() { 
   current = 0; 
   while (SDL_PollEvent(&event)) { 
      switch (event.type) { 
         case SDL_MOUSEMOTION: 
            mousex = event.motion.x; 
            mousey = event.motion.y; 
            break; 
         case SDL_MOUSEBUTTONDOWN: 
            if (event.button.button == SDL_BUTTON_LEFT)
               current = LEFTDOWN; 
            else if (event.button.button == SDL_BUTTON_RIGHT)
               current = RIGHTDOWN;
            break; 
         /* klickar man snabbt kommer denna skriva över LEFTDOWN
         case SDL_MOUSEBUTTONUP: 
            if (event.button.button == SDL_BUTTON_LEFT) 
               current = LEFTUP; 
            else if (event.button.button == SDL_BUTTON_RIGHT) 
               current = RIGHTUP; 
            break;
         */ 
         case SDL_KEYDOWN: 
            current = KEYDOWN; 
            kbInput = event.key.keysym.sym; 
            modInput = event.key.keysym.mod; 
            unicode = event.key.keysym.unicode; 
            break; 
         case SDL_QUIT:
	    std::cout << "Exiting" << std::endl;
            SDL_Quit(); 
            std::exit(0); 
            break; 
      } 
   } 
}

Code: Select all

#include "button.h" 
#include <iostream> 
 
Button::Button(const char *file, int x, int y, void (*function)()) { 
   clicked = false; 
   image.load(file); 
   box.w = image.getWidth(); 
   box.h = image.getHeight(); 
   box.x = x; 
   box.y = y; 
   clickFunction = function; 
} 
 
void Button::update(SDL_Surface *screen) {
   image.show(screen, box.x, box.y); 
   clicked = false; 
   //event.update(); ska enbart köras i main loop:en
    
   if (event.current == LEFTDOWN) { 
      if ((event.getMouseX() > box.x) && (event.getMouseX() < box.x+box.w) 
         && (event.getMouseY() > box.y) && (event.getMouseY() < box.y+box.h)) { 
         clicked = true; 
      } 
   }
    
   if (clicked) 
      clickFunction(); 
}
Lycka till med chipdisken :)
User avatar
jb
Posts: 1076
Joined: 2002-08-08 3:39:12
Location: Karlshamn
Contact:

Post by jb »

straver wrote:Okej,

Problemet var att varje knapp körde sin egen event-loop. Vilket får effekten att den första knappen rensar ut alla events.

En lösning som inte kräver så stora kodförändringar är att göra variablerna i Event static och bara köra bara köra update en gång i main loop:en.

....

Lycka till med chipdisken :)
Tack! :)
Ny låt ---> Jallabert - KRS3
Post Reply