Could anyone break the MyWindow class out into separate MyWindow.h and MyWindow.cpp files from this excellent FLTK example?
I have tried all afternoon. I am stuck on the (void*)this part in the Fl::add_timeout method. I am sure I have other things wrong as well.
I would like to see how the recursion is best handled. Do you MyWindow::RenderImage_CB or leave it as RenderImage_CB?
Adding the code here for convenience.
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// Demonstrate how to display a pixel buffer in FLTK
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
static void RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, RenderImage_CB, userdata);
}
public:
// CTOR
MyWindow(int w, int h, const char *name=0) : Fl_Double_Window(w,h,name) {
end();
RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, RenderImage_CB, (void*)this);
}
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
};
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
Separated this way gives a compiler error:
main.cpp
#include "MyWindow.h"
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
MyWindow.h
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw();
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
void RenderImage_CB(void *userdata);
public:
// CTOR
MyWindow(int w, int h, const char *name=0) : Fl_Double_Window(w,h,name){};
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b);
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage();
};
MyWindow.cpp
#include "MyWindow.h"
void MyWindow::draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
void MyWindow::RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
}
MyWindow::MyWindow(int w, int h, const char *name) : Fl_Double_Window(w,h,name) {
end();
MyWindow::RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, (void*)this);
}
void MyWindow::PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
void MyWindow::RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
Using the above my first error is:
MyWindow.cpp:10:71: error: no matching function for call to 'Fl::repeat_timeout(double, <unresolved overloaded function type>, void*&)'
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
This compiles and runs:
main.cpp
#include "MyWindow.h"
int main(int argc, char**argv) {
Fl::visual(FL_RGB); // prevents dithering on some systems
MyWindow *win = new MyWindow(XSIZE, YSIZE);
win->show();
return(Fl::run());
}
MyWindow.h
#include <FL/Fl.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <stdio.h>
#include <time.h>
#define XSIZE 500
#define YSIZE 500
#define UPDATE_RATE 0.05 // update rate in seconds
// WINDOW CLASS TO HANDLE DRAWING IMAGE
class MyWindow : public Fl_Double_Window {
unsigned char pixbuf[YSIZE][XSIZE][3]; // image buffer
// FLTK DRAW METHOD
void draw();
// TIMER CALLBACK: CALLED TO UPDATE THE DRAWING
static void RenderImage_CB(void *userdata);
public:
// CTOR
MyWindow(int w, int h, const char *name=0);// : Fl_Double_Window(w,h,name){};
// PLOT A PIXEL AS AN RGB COLOR INTO THE PIXEL BUFFER
void PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b);
// MAKE A NEW PICTURE IN THE PIXEL BUFFER, SCHEDULE FLTK TO DRAW IT
void RenderImage();
};
MyWindow.cpp
#include "MyWindow.h"
MyWindow::MyWindow(int w, int h, const char *name) : Fl_Double_Window(w,h,name) {
end();
MyWindow::RenderImage(); // show first drawing
// Start timer updating
Fl::add_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, (void*)this);
}
void MyWindow::draw() {
fl_draw_image((const uchar*)&pixbuf, 0, 0, XSIZE, YSIZE, 3, XSIZE*3);
}
void MyWindow::RenderImage_CB(void *userdata) {
MyWindow *win = (MyWindow*)userdata;
win->RenderImage();
Fl::repeat_timeout(UPDATE_RATE, MyWindow::RenderImage_CB, userdata);
}
void MyWindow::PlotPixel(int x, int y, unsigned char r, unsigned char g, unsigned char b) {
pixbuf[y][x][0] = r;
pixbuf[y][x][1] = g;
pixbuf[y][x][2] = b;
}
void MyWindow::RenderImage() {
static unsigned char drawcount = 0;
for ( int x=0; x<XSIZE; x++ )
for ( int y=0; y<YSIZE; y++ )
PlotPixel(x, y, x+drawcount, y+drawcount, x+y+drawcount);
++drawcount;
redraw();
}
Related
My question is quite related to this thread:
std::unique_ptr with an incomplete type won't compile
I understood the concept of incomplete type with unique_ptr and need to provide the default destructor for the holding class. However, I'm still getting following error:
invalid use of incomplete type ‘class Game::Sprite’
Following is my simplified code. Please let me know if I'm still missing something here? :
/*
* Game.h
*/
#pragma once
#include <string>
#include <unordered_map>
#include "SDL.h"
class Game {
public:
Game();
~Game();
void run();
const int SCREEN_WIDTH = 800;
const int SCREEN_HEIGHT = 600;
private:
void setup();
void loadResources();
void createWorld();
void loop();
window mWindow;
renderer mRenderer;
class Sprite;
using sprite = std::unique_ptr<Sprite>;
sprite mPlayer;
struct Resource {
std::string name;
std::string path;
};
enum class ResourceType {
TEXTURE, IMAGE, AUDIO
};
std::unordered_map<ResourceType, Resource> mResourceList;
std::unordered_map<std::string, texture> mTextureHolder;
};
/*
* Game.cpp
*/
#include <Game.h>
...
#include "Sprite.h"
Game::Game() {
...
}
void Game::run() {
setup();
loadResources();
loop();
}
void Game::setup() {
...
}
void Game::loadResources() {
...
}
void Game::createWorld() {
...
}
void Game::loop() {
bool stop = false;
SDL_Event e;
while (!stop) {
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
stop = true;
}
}
//clear screen
SDL_RenderClear(mRenderer.get());
//render texture
// this gives error:
mPlayer->renderFrame(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0, 0);
//update screen
SDL_RenderPresent(mRenderer.get());
}
}
//default destructor (tried explicit implmentation too)
Game::~Game() = default;
/*
* Sprite.h
*/
#pragm once
#include "SDL.h"
#include <cstdint>
class Sprite {
public:
Sprite(renderer renderer, texture texture, uint32_t width, uint32_t height);
void renderFrame(uint32_t dstX, uint32_t dstY, uint32_t offsetX,
uint32_t offsetY);
void setTexture(texture texture);
private:
renderer mRenderer;
texture mTexture;
uint32_t mWidth;
uint32_t mHeight;
};
/*
* Sprite.cpp
*/
#include "Sprite.h"
Sprite::Sprite(renderer renderer, texture texture, uint32_t width,
uint32_t height) :
mRenderer(renderer), mTexture(std::move(texture)), mWidth(width), mHeight(
height) {
}
void Sprite::renderFrame(uint32_t dstX, uint32_t dstY, uint32_t offsetX,
uint32_t offsetY) {
...
}
void Sprite::setTexture(texture texture) {
...
}
I'm currently working in an app which is essentially a pong game. The game features two paddles currently in rectangular format to ease collision detection against the ball(currently square).
I'm using a "QRect" element as paddle since it provides the ".intersect" method, making it easy to check for collisions.
My implementation for a rectangular paddle is as follows:
Paddle::Paddle(int initial_x, int initial_y) {
QImage image.load(":images/paddle.png");
QRect rect = image.rect();
resetState(initial_x, initial_y);
}
I'm trying to draw an arch like paddle and hitbox, similar to what the code below provides:
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
QPainter painter(this);
painter.drawChord(rectangle, startAngle, spanAngle);
The only problem with the code above is it only works inside a paintEvent function and that won't work for me.
paddle.h
#ifndef PADDLE_H
#pragma once
#include <QImage>
#include <QRect>
class Paddle {
public:
Paddle(int, int);
~Paddle();
public:
void resetState(int, int);
void move();
void setDx(int);
void setDy(int);
QRect getRect();
QImage & getImage();
private:
QImage image;
QRect rect;
int dx;
int dy;
static const int INITIAL_X1 = 70;
static const int INITIAL_Y1 = 350;
};
#define PADDLE_H
#endif // PADDLE_H
paddle.cpp
#include <iostream>
#include "paddle.h"
Paddle::Paddle(int initial_x, int initial_y) {
dy = 0;
image.load(":images/paddle.png");
rect = image.rect();
resetState(initial_x, initial_y);
}
Paddle::~Paddle() {
std::cout << ("Paddle deleted") << std::endl;
}
void Paddle::setDy(int y) {
dy = y;
}
void Paddle::move() {
int x = rect.x();
int y = rect.top() + dy;
rect.moveTo(x, y);
}
void Paddle::resetState(int initial_x, int initial_y) {
rect.moveTo(initial_x, initial_y);
}
QRect Paddle::getRect() {
return rect;
}
QImage & Paddle::getImage() {
return image;
}
mainGame.h
#ifndef BREAKOUT_H
#pragma once
#include <QWidget>
#include <QKeyEvent>
#include <QFrame>
#include "ball.h"
#include "brick.h"
#include "paddle.h"
class Breakout : public QFrame {
Q_OBJECT
public:
Breakout(QWidget *parent = 0);
~Breakout();
signals:
void leftScoreChanged(int leftScore);
void rightScoreChanged(int rightScore);
void ballLost(int ballsLeft);
protected:
void paintEvent(QPaintEvent *);
void timerEvent(QTimerEvent *);
void keyPressEvent(QKeyEvent *);
void keyReleaseEvent(QKeyEvent *);
void drawObjects(QPainter *);
void finishGame(QPainter *, QString);
void moveObjects();
void startGame();
void pauseGame();
void stopGame();
void victory();
void validateScoreChange(int);
void checkCollision();
private:
int x;
int timerId;
int ballsLeft;
int leftScore;
int rightScore;
static const int N_OF_BRICKS = 30;
static const int DELAY = 5;
static const int TOP_EDGE = 0;
static const int LEFT_EDGE = 0;
static const int BOTTOM_EDGE = 700;
static const int RIGHT_EDGE = 1200;
Ball *ball;
Paddle *leftPaddle;
Paddle *rightPaddle;
Brick *bricks[N_OF_BRICKS];
bool gameOver;
bool gameWon;
bool gameStarted;
bool paused;
};
#define BREAKOUT_H
#endif // BREAKOUT_H
Breakout::paintEvent()
void Breakout::paintEvent(QPaintEvent *e) {
Q_UNUSED(e);
QPainter painter(this);
if (gameOver) {
finishGame(&painter, "Game lost");
} else if(gameWon) {
finishGame(&painter, "Victory");
}
else {
drawObjects(&painter);
}
QWidget::paintEvent(e);
}
From what I understand you do not want to load the QImage from a .png file but you want to draw it, if so you can use QPainter to create the image as I show below:
Paddle::Paddle(int initial_x, int initial_y) {
// draw image
QRectF rectangle(10.0, 20.0, 80.0, 60.0);
int startAngle = 30 * 16;
int spanAngle = 120 * 16;
image = QImage(QSize(100, 100), QImage::Format_ARGB32);
image.fill(Qt::transparent);
QPainter painter(&image);
painter.drawChord(rectangle, startAngle, spanAngle);
painter.end();
dy = 0;
rect = image.rect();
resetState(initial_x, initial_y);
}
I am making a SFML framework, and when I use the function loadImage one time, the image loads correctly with all colors, but if I use it two times for another texture, there is only one sprite rendered and it's all white. I read that you don't want to delete the texture or the sprite or it will be white. But in this code I'm storing all the textures in a vector. Does any one know what is wrong in this function?
FM::Image FM::graphics::loadImage(const char* fileName) {
texturesindex++;
sf::Texture texture;
texture.loadFromFile(fileName);
textures.push_back(texture);
sf::Sprite sprite(textures[texturesindex]);
Image image;
image.sprite = sprite;
return image;
}
Here's all the code:
SFFM.cpp:
#include "SFFM.h"
#include <SFML/Graphics.hpp>
#include <vector>
#include <string>
int backgroundcolor[3] = { 0,0,0};
sf::RenderWindow Window(sf::VideoMode(800, 600), "MyGame");
std::vector<sf::Texture> textures;
int texturesindex = -1;
void FM::window::setWindowOptions(unsigned int Width, unsigned int Height, const char* Title, int FrameLimit) {
Window.setSize(sf::Vector2u(Width, Height));
Window.setFramerateLimit(FrameLimit);
Window.setTitle(Title);
}
void FM::window::setBackgroundColor(int r, int g, int b) {
backgroundcolor[0] = r;
backgroundcolor[1] = g;
backgroundcolor[2] = b;
}
FM::Image FM::graphics::loadImage(const char* fileName) {
texturesindex++;
sf::Texture texture;
texture.loadFromFile(fileName);
textures.push_back(texture);
sf::Sprite sprite(textures[texturesindex]);
Image image;
image.sprite = sprite;
return image;
}
void FM::graphics::drawImage(Image image, int x, int y, int scalex, int scaley, int rotation) {
image.sprite.setPosition(x, -y);
image.sprite.setRotation(rotation);
image.sprite.setScale(sf::Vector2f(scalex, scaley));
Window.draw(image.sprite);
}
void FM::graphics::drawImage(Image image, int x, int y, int scalex, int scaley) {
image.sprite.setPosition(x, -y);
image.sprite.setScale(sf::Vector2f(scalex, scaley));
Window.draw(image.sprite);
}
void FM::graphics::drawImage(Image image, int x, int y) {
image.sprite.setPosition(x, -y);
Window.draw(image.sprite);
}
int main()
{
FM::Start();
while (Window.isOpen())
{
sf::Event event;
while (Window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
Window.close();
else if (event.type == sf::Event::Resized)
{
Window.setView(sf::View(sf::FloatRect(0, 0, event.size.width, event.size.height)));
}
}
Window.clear(sf::Color(backgroundcolor[0], backgroundcolor[1], backgroundcolor[2]));
FM::Update();
Window.display();
}
return 0;
}
SFFM.h:
#pragma once
#include <SFML/Graphics.hpp>
namespace FM
{
void Update();
void Start();
class window {
public:
static void setWindowOptions(unsigned int Width, unsigned int Height, const char * Title, int FrameLimit);
static void setBackgroundColor(int r, int g, int b);
};
class Image {
public:
sf::Sprite sprite;
};
class graphics {
public:
static Image loadImage(const char* fileName);
static void drawImage(Image image, int x, int y, int scalex, int scaley, int rotation);
static void drawImage(Image image, int x, int y, int scalex, int scaley);
static void drawImage(Image image, int x, int y);
};
class Input {
public:
};
};
main.cpp:
#include "SFFM.h"
#include <SFML\Graphics.hpp>
FM::Image Gangster;
FM::Image Block;
int x = 0;
int y = 0;
void FM::Start() {
window::setWindowOptions(1280, 720, "Platformer", 120);
window::setBackgroundColor(0, 127, 255);
Gangster = graphics::loadImage("assets/Gangster.png");
}
void FM::Update() {
graphics::drawImage(Gangster, x, y, 5, 5);
graphics::drawImage(Block, 100, 100, 5, 5);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) {
y += 1;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
y -= 1;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
x += 1;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) {
x -= 1;
}
}
Here's a screenshot:
TL;DR Solutions, either:
Use a container other than std::vector<sf::Texture> - std::list<sf::Texture> or std::forward_list<sf::Texture>.
Store pointers to textures - std::vector<std::unique_ptr<sf::Texture>>.
Explanation
You store texture objects along with sprites referring them. This is correct because a spite just keeps a reference (a pointer) to its texture. This also implies that the texture address must remain unchanged during the sprite lifetime.
It looks like you did not take into account how std::vector push_back() works. A vector initally allocates some memory, and once there is no place to insert a new item, the vector allocates more memory and copies all inserted items and the new one there. So all the item addresses change.
In your case an item is a texture, its address is changed upon an isertion of another texture, so some sprite "looses" its texture. This usually results in white squares drawn.
#include "std_lib_facilities_4.h"
#include "Window.h"
#include "Graph.h"
#include "GUI.h"
#include <FL/Fl_Image.H>
using namespace Graph_lib;
using namespace std;
struct Lines_window:Graph_lib::Window{
Lines_window(Point xy, int w, int h, const string& title);
Button button_1;
Button button_2;
static void cb_change_color(Address, Address);
static void cb_change_picture(Address, Address);
};
Lines_window::Lines_window(Point xy, int w, int h, const string& title) :
Window(xy, w, h, title),
button_1(Point(x_max()/2, y_max()/2), 200, 100, "Button 1", cb_change_color),
button_2(Point(x_max()/3, y_max()/3), 200, 100, "Button 2", cb_change_picture)
{
attach(button_1);
attach(button_2);
}
void Lines_window::cb_change_color(Address, Address pw)
{
}
void Lines_window::cb_change_picture(Address, Address pw)
{
}
int main()
try {
if(H112 != 201401L)error("Error: incorrect std_lib_facilities_4.h version ", H112);
using namespace Graph_lib;
Lines_window win(Point(100,100),600,400,"Buttons");
return gui_main();
return 0;
}
catch(exception& e) {
cerr << "exception: " << e.what() << '\n';
return 1;
}
catch (...) {
cerr << "Some exception\n";
return 2;
}
This is my button code. I am trying to make two buttons, one that changes color when you press it and another that puts an image on the button when you press it. I haven't made a callback yet because this won't compile. Errors are:
GUI.cpp:16:6: error: prototype for ‘void Graph_lib::Button::attach(Graph_lib::Window&, Fl_Color)’ does not match any in class ‘Graph_lib::Button’
void Button::attach(Window& win, Fl_Color color)
^
In file included from GUI.cpp:10:0:
GUI.h:66:14: error: candidate is: virtual void Graph_lib::Button::attach(Graph_lib::Window&)
void attach(Window&);
^
Do I need callbacks to compile? I am basing this code off of my professor's code here. I took everything out except for the buttons so I could make them. The GUI.cpp and GUI.h were given to us. What am I doing wrong?
GUI.cpp
//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//
#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Output.H>
#include "GUI.h"
namespace Graph_lib {
//------------------------------------------------------------------------------
void Button::attach(Window& win, Fl_Color color)
{
pw = new Fl_Button(loc.x, loc.y, width, height, label.c_str());
pw->color(BLUE);
pw->callback(reinterpret_cast<Fl_Callback*>(do_it), &win); // pass the window
own = &win;
}
//------------------------------------------------------------------------------
int In_box::get_int()
{
Fl_Input& pi = reference_to<Fl_Input>(pw);
// return atoi(pi.value());
const char* p = pi.value();
if (!isdigit(p[0])) return -999999;
return atoi(p);
}
//------------------------------------------------------------------------------
string In_box::get_string()
{
Fl_Input& pi = reference_to<Fl_Input>(pw);
return string(pi.value());
}
//------------------------------------------------------------------------------
void In_box::attach(Window& win)
{
pw = new Fl_Input(loc.x, loc.y, width, height, label.c_str());
own = &win;
}
//------------------------------------------------------------------------------
void Out_box::put(const string& s)
{
reference_to<Fl_Output>(pw).value(s.c_str());
}
//------------------------------------------------------------------------------
void Out_box::attach(Window& win)
{
pw = new Fl_Output(loc.x, loc.y, width, height, label.c_str());
own = &win;
}
//------------------------------------------------------------------------------
int Menu::attach(Button& b)
{
b.width = width;
b.height = height;
switch(k) {
case horizontal:
b.loc = Point(loc.x+offset,loc.y);
offset+=b.width;
break;
case vertical:
b.loc = Point(loc.x,loc.y+offset);
offset+=b.height;
break;
}
selection.push_back(b); // b is NOT OWNED: pass by reference
return int(selection.size()-1);
}
//------------------------------------------------------------------------------
int Menu::attach(Button* p)
{
Button& b = *p;
b.width = width;
b.height = height;
switch(k) {
case horizontal:
b.loc = Point(loc.x+offset,loc.y);
offset+=b.width;
break;
case vertical:
b.loc = Point(loc.x,loc.y+offset);
offset+=b.height;
break;
}
selection.push_back(&b); // b is OWNED: pass by pointer
return int(selection.size()-1);
}
//------------------------------------------------------------------------------
} // of namespace Graph_lib
GUI.h
//
// This is a GUI support code to the chapters 12-16 of the book
// "Programming -- Principles and Practice Using C++" by Bjarne Stroustrup
//
#ifndef GUI_GUARD
#define GUI_GUARD
#include "Window.h"
#include "Graph.h"
namespace Graph_lib {
//------------------------------------------------------------------------------
typedef void* Address; // Address is a synonym for void*
typedef void(*Callback)(Address, Address); // FLTK's required function type for all callbacks
//------------------------------------------------------------------------------
template<class W> W& reference_to(Address pw)
// treat an address as a reference to a W
{
return *static_cast<W*>(pw);
}
//------------------------------------------------------------------------------
class Widget {
// Widget is a handle to an Fl_widget - it is *not* an Fl_widget
// We try to keep our interface classes at arm's length from FLTK
public:
Widget(Point xy, int w, int h, const string& s, Callback cb)
: loc(xy), width(w), height(h), label(s), do_it(cb)
{}
virtual void move(int dx,int dy) { hide(); pw->position(loc.x+=dx, loc.y+=dy); show(); }
virtual void hide() { pw->hide(); }
virtual void show() { pw->show(); }
virtual void attach(Window&) = 0;
Point loc;
int width;
int height;
string label;
Callback do_it;
virtual ~Widget() { }
protected:
Window* own; // every Widget belongs to a Window
Fl_Widget* pw; // connection to the FLTK Widget
private:
Widget& operator=(const Widget&); // don't copy Widgets
Widget(const Widget&);
};
//------------------------------------------------------------------------------
struct Button : Widget {
Button(Point xy, int w, int h, const string& label, Callback cb)
: Widget(xy,w,h,label,cb)
{}
void attach(Window&);
};
//------------------------------------------------------------------------------
struct In_box : Widget {
In_box(Point xy, int w, int h, const string& s)
:Widget(xy,w,h,s,0) { }
int get_int();
string get_string();
void attach(Window& win);
};
//------------------------------------------------------------------------------
struct Out_box : Widget {
Out_box(Point xy, int w, int h, const string& s)
:Widget(xy,w,h,s,0) { }
void put(int);
void put(const string&);
void attach(Window& win);
};
//------------------------------------------------------------------------------
struct Menu : Widget {
enum Kind { horizontal, vertical };
Menu(Point xy, int w, int h, Kind kk, const string& label)
: Widget(xy,w,h,label,0), k(kk), offset(0)
{}
Vector_ref<Button> selection;
Kind k;
int offset;
int attach(Button& b); // Menu does not delete &b
int attach(Button* p); // Menu deletes p
void show() // show all buttons
{
for (unsigned int i = 0; i<selection.size(); ++i)
selection[i].show();
}
void hide() // hide all buttons
{
for (unsigned int i = 0; i<selection.size(); ++i)
selection[i].hide();
}
void move(int dx, int dy) // move all buttons
{
for (unsigned int i = 0; i<selection.size(); ++i)
selection[i].move(dx,dy);
}
void attach(Window& win) // attach all buttons
{
for (int i=0; i<selection.size(); ++i) win.attach(selection[i]);
own = &win;
}
};
//------------------------------------------------------------------------------
} // of namespace Graph_lib
#endif // GUI_GUARD
I found the answer. It wouldn't compile because I added an argument to be passed to button (the Fl_Color). I will have to figure out a way to pass a value to the button to change the color.
my code is not really working (no errors, but the rectangle is not shown).
I have 3 classes: CFramework, CRectangle, CGame.
Whats wrong/missing?
My CFramework class initiates SDL and sets the video mode etc.
CRectangle.hpp:
#ifndef RECTANGLE_HPP
#define RECTANGLE_HPP
#include "Framework.hpp"
class CRectangle
{
public:
CRectangle ();
void createRectangle (int x, int y, int width, int height, int r, int g, int b);
private:
SDL_Surface *m_pScreen; // Pointer at the screen of CFramework
SDL_Rect m_Rect;
};
#endif
CRectangle.cpp:
#include "Rectangle.hpp"
// Konstruktor
//
// Aufgabe: Zeiger auf Screen holen
//
CRectangle::CRectangle ()
{
// Zeiger auf Screen holen
m_pScreen = g_pFramework->GetScreen ();
} // Konstruktor
// createRectangle
//
// Aufgabe: Viereck erstellen
//
void CRectangle::createRectangle (int x, int y, int width, int height, int r, int g, int b)
{
m_Rect.x = x;
m_Rect.y = y;
m_Rect.w = width;
m_Rect.h = height;
SDL_FillRect(m_pScreen, &m_Rect, SDL_MapRGB(m_pScreen->format, r, g, b));
} // createRectangle
CGame.cpp:
... // just the important stuff
m_pRectangleMenu = new CRectangle;
m_pRectangleMenu->createRectangle(100,100,400,400,233,34,34);
...
// just the important stuff
m_pRectangleMenu = new CRectangle;
m_pRectangleMenu->createRectangle(100,100,400,400,233,34,34);
Well since you didn't include an "SDL_Flip(screen_variable)"...maybe that's your problem. If not, you should post up unto the SDL_Flip().
Reagan