I have a container of objects:
std::vector<sf::Drawable> gameObjects;
My goal is to iterate through these objects and draw them:
for (auto it : gameObjects)
{
window.draw(*it);
}
You can assume these methods are already implemented. What I mean by 'animate': I want these objects drawn one at a time, rather than all at once immediately.
void Run::render()
{
window.clear(colorWindow);
for (auto it : gameObjects)
{
window.draw(*it);
}
window.display();
}
That is, have every render() draw an additional object in the container. Do you know how I can go about doing this? Thank you in advance.
edit: I've tried something unconventional - I dont think it's good practice, but it works:
int count = 0;
int countReset = 1;
...
while (countReset > count)
{
objects.at(count++).draw(window);
}
countReset++;
count = 0;
You should never make decisions about your game in your rendering. You should have an update method somewhere, that makes decisions on how input and time passed affect your game world. Rendering should only do one thing: rendering. No decision making, no data manipulation.
You could for example use a compound class to indicate which object should be drawn or you could derive your own base class from sf::Drawable and implement a bool IsVisible() const; method. Either way, the decision if it's drawn is made elsewhere, the rendering is only executing commands what to render specifically:
struct MaybeDrawn
{
bool IsVisible;
sf::Drawable Object;
};
...
std::vector<MaybeDrawn> gameObjects;
...
void Run::render()
{
window.clear(colorWindow);
for (auto it : gameObjects)
{
if(it->IsVisible)
{
window.draw(it->Object);
}
}
window.display();
}
Your decision, how and when to set the bool to true should happen in your Update/ChangeWorld method. Maybe you want to have a look here for a general description on how to structure a game and how to build a timer.
Alternatively, you could leave your program as it is and insert and/or delete from your vector in your decision making method.
Use a static counter for your index in list of objects. Measure time and incremente the counter if a time period has elapsed. So next time is drawn next object in list.
#include <chrono>
void Run::render()
{
// actual time
std::chrono::high_resolution_clock::time_point actTime = std::chrono::high_resolution_clock::now();
// remember time
static bool init = false;
std::chrono::high_resolution_clock::time_point lastTime;
if ( !init )
{
lastTime = actTime;
init = true;
}
// delta time
long microseconds = std::chrono::duration_cast<std::chrono::duration<long, std::micro> >( actTime - lastTime ).count();
double deltaTms = ((double)microseconds) / 1000.0;
window.clear(colorWindow);
static size_t actObjInx = 0;
window.draw(gameObjects[actObjInx]);
// increment object index if time period has elapsed
if ( deltaTms > 100.0 ) // 0.1 seconds
{
lastTime = actTime;
actObjInx ++;
if ( actObjInx == gameObjects.size() )
actObjInx = 0;
}
window.display();
}
Related
Using GTKMM, I'm extending the DrawingArea widget with the idea that an external process provides it with images. My CameraDrawingArea will then display the images at the right size using Cairo.
Each time an image arrives, I store it and I call the invalidate method, which eventually ends up in a call to on_draw, where I can resize and display the image.
My problem is the following:
The first 10 or 20 images are displayed as I expected.
After a while, the images keep coming from the provider process, I keep calling invalidate
but on_draw is not called any more.
To show it here, I've simplified the code so that there is nothing external to the class, and no link with other libraries. I've replaced the process providing the images by a method with for-loops, and the display of the image by printing a simple text in the middle of the widget area:
In the constructor I launch a new std::thread to call the doCapture method in the same instance. I also set up a font description, to use it later.
The doCapture method is a silly CPU eater, that does nothing except calling from time to time the refreshDrawing method, as long as keepCapturing is not false.
refreshDrawing invalidates the whole window's rectangle via a call to invalidate.
Gtk's magic is suppose to call on_draw and provide a Cairo context to draw whatever. In my case, for tests purposes, I draw a brownish centered integer.
The class destructor stops the thread by set keepCapturing to false, and waits for termination with a join.
#include "camera-drawing-area.hpp"
#include <iostream>
CameraDrawingArea::CameraDrawingArea():
captureThread(nullptr) {
fontDescription.set_family("Monospace");
fontDescription.set_weight(Pango::WEIGHT_BOLD);
fontDescription.set_size(30 * Pango::SCALE);
keepCapturing = true;
captureThread = new std::thread([this] {
doCapture();
});
}
void CameraDrawingArea::doCapture() {
while (keepCapturing) {
float f = 0.0;
for (int n = 0; n < 1000; n++) {
for (int m = 0; m < 1000; m++) {
for (int o = 0; o < 500; o++) {
f += 1.2;
}
}
}
std::cout << "doCapture - " << f << std::endl;
refreshDrawing();
}
}
void CameraDrawingArea::refreshDrawing() {
auto win = get_window();
if (win) {
win->invalidate(false);
std::cout << "refreshDrawing" << std::endl;
}
}
bool CameraDrawingArea::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) {
std::cout << "on_draw" << std::endl;
static char buffer[50];
static int n = 0;
sprintf(buffer, "-%d-", n++);
Gtk::Allocation allocation = get_allocation();
const int width = allocation.get_width();
const int height = allocation.get_height();
auto layout = create_pango_layout(buffer);
layout->set_font_description(fontDescription);
int textWidth, textHeight;
layout->get_pixel_size(textWidth, textHeight);
cr->set_source_rgb(0.5, 0.2, 0.1);
cr->move_to((width - textWidth) / 2, (height - textHeight) / 2);
layout->show_in_cairo_context(cr);
cr->stroke();
return true;
}
CameraDrawingArea::~CameraDrawingArea() {
keepCapturing = false;
captureThread->join();
free(captureThread);
}
And this is my header file:
#ifndef CAMERA_DRAWING_AREA_HPP
#define CAMERA_DRAWING_AREA_HPP
#include <gtkmm.h>
#include <thread>
class CameraDrawingArea : public Gtk::DrawingArea {
public:
CameraDrawingArea();
virtual ~CameraDrawingArea();
protected:
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private:
bool keepCapturing;
void doCapture();
void refreshDrawing();
std::thread* captureThread;
Pango::FontDescription fontDescription;
};
#endif
The problem manifests itself as follows:
When starting the application, it faithfully displays 1, 2, 3...
Between 5th and 20th iteration (it's random, but rarely outside these ranges), it stops refreshing.
Because of the cout, I can see that refreshDrawing is called be sure that invalidate is also called, but on_draw isn't.
Also, if I stop the application before it stops refreshing, then it ends up nicely. But, if I stop the application after it stops refreshing, then I see this message below (the ID value varies):
GLib-CRITICAL **: 10:05:04.716: Source ID 25 was not found when attempting to remove it
I'm quite sure that I do something wrong, but clueless about what. Any help would be appreciated.
I also checked the following questions, but they don't seem to be related with my case:
Draw signal doesn't get fired in GTKMM, when derived class doesn't call a superclass's constructor
You can't use GTK methods from any other thread than the one in which you started the GTK main loop. Probably the win->invalidate() call is causing things to go wrong here.
Instead, use Glib::Dispatcher to communicate with the main thread, or use gdk_threads_add_idle() for a more C-style solution.
Based on the answer form #ptomato, I've rewritten my example code. The golden rule is do not call GUI functions from another thread, but if you do, then acquire some specific GDK locks first. That's the purpose of Glib::Dispatcher :
If a Glib::Dispatcher object is constructed in the main GUI thread (which will therefore be the receiver thread), any worker thread can emit on it and have the connected slots safely execute gtkmm functions.
Based on that, I've added a new private member Glib::Dispatcher refreshDrawingDispatcher that will allow threads to safely the invalidate the windows area:
#ifndef CAMERA_DRAWING_AREA_HPP
#define CAMERA_DRAWING_AREA_HPP
#include <gtkmm.h>
#include <thread>
class CameraDrawingArea :
public Gtk::DrawingArea {
public:
CameraDrawingArea();
virtual ~CameraDrawingArea();
protected:
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
private:
bool keepCapturing;
void doCapture();
void refreshDrawing();
Glib::Dispatcher refreshDrawingDispatcher;
std::thread* captureThread;
Pango::FontDescription fontDescription;
};
#endif
Then, I've connected the dispatcher to the refreshDrawing method. I do this in the class constructor, which is called during GUI start up and therefore in the main GUI thread:
CameraDrawingArea::CameraDrawingArea():
refreshDrawingDispatcher(),
captureThread(nullptr) {
fontDescription.set_family("Monospace");
fontDescription.set_weight(Pango::WEIGHT_BOLD);
fontDescription.set_size(30 * Pango::SCALE);
keepCapturing = true;
captureThread = new std::thread([this] {
doCapture();
});
refreshDrawingDispatcher.connect(sigc::mem_fun(*this, &CameraDrawingArea::refreshDrawing));
}
Finally, the thread has to call the dispatcher:
void CameraDrawingArea::doCapture() {
while (keepCapturing) {
float f = 0.0;
for (int n = 0; n < 1000; n++) {
for (int m = 0; m < 1000; m++) {
for (int o = 0; o < 500; o++) {
f += 1.2;
}
}
}
std::cout << "doCapture - " << f << std::endl;
refreshDrawingDispatcher.emit();
}
}
And now, this works without further problems.
I'm working on a new project and an implementing a basic scene change. I have the different scenes setup as their own classes, with the intialisation function being used to create and reposition different SFML objects. I saw this answer and have written my scene switcher similarly:
// Create scene monitoring variable
int scene[2];
scene[0] = 0; // Set current scene to menu
scene[1] = 0; // Set scene change to no
...
// Check for scene change
if(scene[1] == 0) {
// Run tick function based on current scene
switch(scene[0]) {
case 0:
// Main menu - run tick function
menu.tick();
}
}
if(scene[1] == 1) {
// Reset scene that you've changed to
switch(scene[0]) {
case 0:
// Main menu - reset it
menu = Menu(window, scene); // <-- Reinitialise menu here
}
// Set change variable to 0
scene[1] = 0;
}
You can see the full code on the github repository.
However, this doesn't seem to work properly - as soon as a scene change is made, the screen goes blank. The class is reintialised (I added a cout to check), the draw function is still run and mouse clicks are still processed, yet nothing appears in the window.
Am I doing something wrong here?
Doing things that way can lead into leak memory errors. I suggest you a different approach: the StateStack
How this works?
The basics of having a StateStack object is store each possible state of your game/app into a stack. This way, you can process each one in the stack order.
What is an State?
An State is something that can be updated, drawn and handle events. We can make an interface or an abstract class to make our screens behave like a State.
Which are the advantages?
With a stack structure, you can easily control how your different scenes are going to handle the three different processing methods. For instance. If you have a mouse click while you're in a pause menu, you won't that click event to reach the menu state or the "game" state. To achieve this, the solution is really easy, simply return false in your handleEvent method if you don't want the event go further this particular state. Note that this idea is also expandable to draw or update methods. In your pause menu, you won't update your "game" state. In your "game" state you won't draw tour menu state.
Example
With this points in mind, this is one possible way of implementation. First, the State interface:
class State{
public:
virtual bool update() = 0;
virtual bool draw(sf::RenderTarget& target) const = 0;
// We will use a vector instead a stack because we can iterate vectors (for drawing, update, etc)
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack) = 0;
};
Following this interface we can have a example MenuState and PauseState:
MenuState
class MenuState : public State{
public:
MenuState(){
m_count = 0;
m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("MenuState: " + std::to_string(m_count));
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);
}
virtual bool update() {
m_count++;
m_text.setString("MenuState: " + std::to_string(m_count));
return true;
}
virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
return true;
}
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::P){
stack.push_back(new PauseState());
return true;
}
}
return true;
}
private:
sf::Font m_font;
sf::Text m_text;
unsigned int m_count;
};
PauseState
class PauseState : public State{
public:
PauseState(){
sf::Font f;
m_font.loadFromFile("Roboto-Regular.ttf");
m_text.setFont(m_font);
m_text.setString("PauseState");
m_text.setPosition(10, 10);
m_text.setFillColor(sf::Color::White);
}
virtual bool update() {
// By returning false, we prevent States UNDER Pause to update too
return false;
}
virtual bool draw(sf::RenderTarget &target) const{
target.draw(m_text);
// By returning false, we prevent States UNDER Pause to draw too
return false;
}
virtual bool handleEvent(sf::Event e, std::vector<State*> &stack){
if (e.type == sf::Event::KeyPressed){
if (e.key.code == sf::Keyboard::Escape){
stack.pop_back();
return true;
}
}
return false;
}
private:
sf::Font m_font;
sf::Text m_text;
};
By the way, while I was doing this, I notice that you must have the fonts as an attribute of the class in order to keep the reference. If not, when your text is drawn, its font is lost ant then it fails. Another way to face this is using a resource holder, which is much more efficient and robust.
Said this, our main will look like:
Main
int main() {
// Create window object
sf::RenderWindow window(sf::VideoMode(720, 720), "OpenTMS");
// Set window frame rate
window.setFramerateLimit(60);
std::vector<State*> stack;
// Create menu
stack.push_back(new MenuState());
// Main window loops
while (window.isOpen()) {
// Create events object
sf::Event event;
// Loop through events
while (window.pollEvent(event)) {
// Close window
if (event.type == sf::Event::Closed) {
window.close();
}
handleEventStack(event, stack);
}
updateStack(stack);
// Clear window
window.clear(sf::Color::Black);
drawStack(window, stack);
// Display window contents
window.display();
}
return 0;
}
The stack functions are simple for-loop but, with the detail that iterate the vector backwards. This is the way to imitate that stack behavior, starting from top (size-1 index) and ending at 0.
Stack functions
void handleEventStack(sf::Event e, std::vector<State*> &stack){
for (int i = stack.size()-1; i >=0; --i){
if (!stack[i]->handleEvent(e, stack)){
break;
}
}
}
void updateStack(std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->update()){
break;
}
}
}
void drawStack(sf::RenderTarget &target, std::vector<State*> &stack){
for (int i = stack.size() - 1; i >= 0; --i){
if (!stack[i]->draw(target)){
break;
}
}
}
You can learn more about StateStacks and gamedev in general with this book
I'm creating a simple game with qt 5.0.1. It's something like Warblade.
I have problem with creating waves of enemies.
int k;
int pos = 100;
for (k = 0; k < 5; k++)
{
pos = 100;
for (int i = 0; i < 9; i++)
{
player->spawn_in_pos(pos);
pos += 100;
}
//QThread::sleep(2);
}
When i use sleep() function, my game just can't run. It's waiting for loop finish and then it shows.
I'm also dealing with second option:
QTimer * timer = new QTimer();
QObject::connect( timer, SIGNAL(timeout()), player, SLOT(spawn_in_pos(pos)) );
timer->start(450);
But it looks like SLOT can't get the position.
Edit:
I just did what #ddriver said, and that helped me a lot.
Now I'm getting some 'laggy' style enemies movement.
Edit2:
I'm moving my enemies down like this:
setPos(x(),y()+1);
with that timer:
// connect
QTimer * timer = new QTimer(this);
connect(timer,SIGNAL(timeout()),this,SLOT(move()));
// start the timer
timer->start(10);
It looks like very smooth movement but probably +1 pixel down and a 10 timer is to less:((
I'm not sure what you are trying to achieve, but in your second option, you cannot get the position, because the timeout doesn't send it.
The signal is timeout(void) and your slot expects an parameter. I guess you lack some basic understanding of the signal/slot mechanism.
The QT Documentation is pretty neat:
http://doc.qt.io/qt-5/signalsandslots.html
And if you just want to create a game out of nothing, here you can find a little tutorial, how to write games in QT:
https://www.youtube.com/watch?v=8ntEQpg7gck
Calling sleep is going to stop the thread from processing anything, which is not what you want to do.
Using C++ 11, you can use the QTimer with a lambda function like this: -
int pos = 100;
int nextWaveTime = 2000; // 2 seconds per wave
for (k = 0; k < 5; k++) // 5 waves of enemies
{
for (int i = 0; i < 9; i++) // 9 enemies per wave
{
QTimer * timer = new QTimer();
timer->setSingleShot(true);
pos = pos + (100*i); // set the pos, which is captured by value, in the lambda function
QObject::connect( timer, QTimer::timeout, [=](){
player->spawn_in_pos(pos);
timer->deleteLater(); // must cleanup the timer
});
timer->start(450 + (k*nextWaveTime));
}
}
In order to pass parameters with signals and slots in Qt, the signal parameters must match the parameters of the slot (or function since Qt 5).
One way to solve the issue is to use a lambda as in TheDarkKnight's answer.
What I would suggest is to use encapsulation - you could create a Spawner object, dedicated to spawning enemies and keep the position internal to it. This way the spawner will manage the position, and you can have something like Spawner::createWave() slot with no parameters, since the position is internal. Then setup the timer and connect it to createWave() and you are set.
Also it is a very bad idea to hardcode stuff like that, you really need more flexibility, the option to change enemy and wave count, the wave time as well as the screen width, so that your game can change those things as it gets harder.
class Spawner : public QObject {
Q_OBJECT
public:
Spawner(int wCount = 5, int eCount = 9, int time = 2000, int sWidth = 1000)
: waveCount(wCount), enemyCount(eCount), currentWave(0), screenWidth(sWidth) {
timer.setInterval(time);
connect(&timer, SIGNAL(timeout()), this, SLOT(createWave()));
}
void set(int wCount, int eCount, int time) {
timer.setInterval(time);
waveCount = wCount;
enemyCount = eCount;
}
void changeWidth(int w) { screenWidth = w; }
public slots:
void start() { timer.start(); }
void stop() {
timer.stop();
currentWave = 0;
}
private slots:
void createWave() {
int pos = screenWidth / (enemyCount + 1);
int step = pos;
for (int i = 0; i < enemyCount; ++i) {
Game::spawnEnemyAt(pos);
pos += step;
}
if (++currentWave >= waveCount) stop();
}
private:
QTimer timer;
int waveCount, enemyCount, currentWave, screenWidth;
};
Create a Spawner object and connect the game new level to start() - it will span the given number waves of enemies evenly across the game screen, when you finish the waves off, you adjust the spawner settings and start a new level.
That encapsulation will come in handy later on as your game becomes less of a test and more like a real game - with increasing difficulty, changing spawning and attack patterns and so on. So it is a good idea to implement it right from the start and build upon a good and flexible design rather than going back and changing stuff around, which may break other code. You really don't want to start without a good design and make design changes later. Thus the need to encapsulate functionality and responsibility and just connect the pieces rather than building on a pile of spaghetti code. In this line of thought, I noticed you are using player->spawn_in_pos(pos); - which is an example of bad design, as spawning should be a responsibility of the Game class, not the Player class. A good design is not only flexible, but also clean. The Spawner object is only responsible for spawning waves of enemies, and its visible interface is limited to start(), stop() and set().
Edit:
class Game : public QObject {
Q_OBJECT
public:
Game() {
if (!scene) scene = new QGraphicsScene(this);
connect(this, SIGNAL(newLevel()), &spawner, SLOT(start()));
}
static void spawnEnemyAt(int x = 0) {
scene->addItem(new Enemy(x, 0));
qDebug() << "enemy created";
}
public slots:
void newGame() {
// initialize game
emit newLevel(); // begin spawning
}
void onLevelEnd() {
// spawner.set(new level settings);
emit newLevel();
}
void onGameEnded() {
// ...
}
signals:
void newLevel();
private:
Spawner spawner;
static QGraphicsScene * scene;
};
// in game.cpp
QGraphicsScene * Game::scene = nullptr;
If you don't want to use static members, you can make spawnEnemyAt() and scene instance members, but then you will have to pass the Game instance to the Spawner in the constructor so that you have a reference to the game the spawner operates on and use game->spawnEnemyAt() instead. This way you can create multiple games with their own dedicated scenes. Or parent the spawner to the game and cast the spawner's parent() to a Game * to access the game instance which is a little hacky, but saves on the extra member by reusing the parent.
I am porting a game from cocos2d-iphone 2.x to cocos2d-x 3.x.
Have to solve a few problems, including a major crash - the subject of this post.
It has been determined that the crash happens because SOMETIMES, my replaceScene call results in a messed-up important public variable.
My class:
class Player : public cocos2d::Sprite
{
public:
....
cocos2d::Vec2 desiredPosition;
....
My Layer methods:
Scene* GameLevelLayer::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto layer = GameLevelLayer::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
bool GameLevelLayer::init()
{
// super init first
if ( !Layer::init() )
{
return false;
}
....
player = (Player*) cocos2d::Sprite::create("sprite_idle_right#2x.png");
player->setPosition(Vec2(100, 50));
player->desiredPosition = player->getPosition();
....
this->schedule(schedule_selector(GameLevelLayer::update), 1.0/60.0);
....
return true;
}
void GameLevelLayer::endGame(bool won) {
....
MenuItem* display;
if (currentLevel < lastLevel && won) {
++currentLevel;
display = MenuItemImage::create("next.png" ,"next.png" ,"next.png",
CC_CALLBACK_1(GameLevelLayer::replaceSceneCallback, this));
} else {
// Lost the game
currentLevel = 1;
display = MenuItemImage::create("replay.png", "replay.png", "replay.png",
CC_CALLBACK_1(GameLevelLayer::replaceSceneCallback, this));
}
....
}
void GameLevelLayer::replaceSceneCallback(Ref* sender) {
Director::getInstance()->replaceScene(this->createScene());
}
The member being messed is the desiredPosition. It is changed inside update() method. The problem is that update() gets an already messed-up desired position. It is only messed-up after a scene was being replaced. The problem happens once in 10 runs, or so. It even appears that when update() is called first time after the scene has been replaced, desiredPosition set to some garbage. is I was unable to learn more.
My Player class does not have a separate constructor.
Please advise.
I forgot to initialize another instance variable. That instance variable is used to calculate the desiredPosition.
I'm capable to fill the database table in wxListCtrl,
my problem is to handle high range of data, I want to do this with the help of thread concept , perhaps it will save to hang the frame because of high amount of data.
I'm new in thread concept so your single lines will be a book for me.
Update:
My question was- how to display large data in wxListCtrl with using concept of wxThread
so for this I used thread concept I add two more files thread.c and thread.cpp
my entry thread code is shown below
void *MyThread :: Entry()
{
int i=1,j,k=0;
while(i!=400)
{
long index=this->temp->data_list_control->InsertItem(i,wxT("amit"));
for(j=1; j<3; j++) {
this->temp->data_list_control->SetItem(index,j,wxT("pathak"));
}
k++;
if(k==30) {
this->Sleep(1000);
k=0;
}
i++;
}
}
It is sometimes working fine but when I try to increase the value of i, it shows an error like
-*showingdatainwxlistctrl: ../../src/XlibInt.c:595: _XPrivSyncFunction: Assertion `dpy->synchandler == _XPrivSyncFunction' failed.*
or sometime it gives error like
***[Xcb] xcb_io.c:378: _XAllocID: Assertion `ret != inval_id' failed***
Why it is happening to me?
You can define your own thread object in wxWidgets in the following way:
class MyThread : public wxThread
{
private:
wxListCtrl* m_pListCtrl;
public:
MyThread(wxListCtrl* pListCtrl, wxThreadKind kind = wxTHREAD_DETACHED) :
wxThread(kind), m_pListCtrl(pListCtrl) {
}
virtual ~MyThread() {
}
virtual void* Entry() {
// here you have to place your code that will be running in separate thread
// m_pListCtrl-> ...
}
};
And this is the way how you can start your thread (assume you have your pListCtrl pointer here):
MyThread * pMyThread = new MyThread (pListCtrl);
wxThreadError ThreadError = pMyThread->Create();
if (wxTHREAD_NO_ERROR!=ThreadError) {
wxLogError(L"Can not create thread, wxThreadError '%d'", (int)ThreadError);
delete pMyThread;
return false;
}
ThreadError = pMyThread->Run();
if (wxTHREAD_NO_ERROR!=ThreadError) {
wxLogError(L"Can not run thread, wxThreadError '%d'", (int)ThreadError);
delete pMyThread;
return false;
}
// here, everything is ok.
Anyway, this is not the best solution for your problem. As far as I've understood, you need to display large amount of data in your wxListCtrl. To do this, you can use virtual ctrl (created with flag wxLC_VIRTUAL) and provide data source:
class MyListCtrl : public wxListCtrl
{
public:
MyListCtrl( ...) { ... }
virtual ~MyListCtrl();
protected:
virtual int OnGetItemImage(long item) const {
// You need this only if you want to provide specific image for your item.
// If you do not need it, just do not overload this method.
}
virtual wxString OnGetItemText(long item, long column) const {
// This is where you have to provide data for [item, column].
// Suppose, you have matrix A[n,m] which represents actually the data
// you want to display. The elements of this matrix can be of any type
// (strings, doubles, integers etc).
// You should return here wxString object that contains
// representation of the matrix's element A[item, column].
return ToWxString(A[item, column]);
// where ToWxString is your method that converts data to string
// So, you do not need to load all the data from A to wxListCtrl.
// Instead of it, wxListCtrl will determine which rows of the matrix should be
// displayed based on sizes and scroll position of wxListCtrl, and will
// call this method to obtain corresponding strings.
}
};
To create, you may use:
m_pListCtrl = new MyListCtrl( ..., ..., wxLC_REPORT | wxLC_SINGLE_SEL | wxLC_VIRTUAL | wxSUNKEN_BORDER | wxLC_VRULES | wxLC_HRULES);
Best regards!
When you are performing high range of data you are bound to use WXThread in your program
Firstly was trying to fill wxListCtrl from wxEntry point, it was wrong u can not hit any main thread control from entry point, it does not give error, but it is a wrong concept
Here u need to pass the data to handler, handler will use it to fill wxListCtrl
code look like this->
void *MyThread :: Entry()
{
int a;
Handler handler_obj;
char *database_name=DATABASE_NAME;
connection =handler_obj.handler(101,database_name);
if(connection==NULL)
{
wxMessageBox(wxT("CAN NOT CONNECT TO DATABASE"), wxT("Message"), wxOK | wxICON_INFORMATION, NULL, -1, -1);
}
else
{
List_Ctrl_Data list_ctrl_data_object;
table_data=list_ctrl_data_object.fetch_table(connection);
MYSQL_ROW row;
while((row=mysql_fetch_row(table_data))!=NULL)
{
wxCommandEvent event( wxEVT_COMMAND_TEXT_UPDATED, 100000 );
void *row_data;
row_data=(void *)row;
event.SetClientData(row_data);
temp->GetEventHandler()->AddPendingEvent( event );
this->Sleep(1000);
}
}
}
to handle the row data we will use
void Id_Search_Report::onNumberUpdate(wxCommandEvent& evt)
{
int j;
void* hold_row;
hold_row=(void *)evt.GetClientData();
MYSQL_ROW row;
row=(MYSQL_ROW)hold_row;
const char* chars1 = row[0];
wxString mystring1(chars1, wxConvUTF8);
long index=data_list_control->InsertItem(this->counter,mystring1);
this->counter++;
for(j=1;j<12;j++)
{
const char* chars2=row[j];
wxString mystring2(chars2,wxConvUTF8);
data_list_control->SetItem(index,j,mystring2);
}
}
thread is returning a row , this method will handle the row and fill ListCtrl , it is a proper way to fill wxListCtrl.