Animation i wxWidgets [wxTimer, wxTextFile]

If you are using the main C++ distribution of wxWidgets, Feel free to ask any question related to wxWidgets development here. This means questions regarding to C++ and wxWidgets, not compile problems.
Post Reply
klaudiaf24
In need of some credit
In need of some credit
Posts: 1
Joined: Fri May 31, 2019 3:36 pm

Animation i wxWidgets [wxTimer, wxTextFile]

Post by klaudiaf24 » Sat Jun 01, 2019 10:49 am

I would like to point out that I'm new to wxWidgets library. I want to write a programme in C++ that will make few short anitmations.
It will take the lines with commands from .txt file as below:

Code: Select all

800 600			//size
1 20 				//number of frame and time as millisec
KP 255 0 0			// wxColor(255,0,0) to for example set Pen's Color
EL 100 250 500 50 	// to dc.DrawEllipse(100, 250, 500, 50);
stop				// end FIRST frame
2 40				// 2nd frame
RP 5
KP 255 0 255
EL 10 25 50 50 0
stop				//end 2rd frame
3 50				// 3rd frame
KP 255 255 0
EL 130 50 100 50 0
stop				//end 3rd frame
END				//end .txt file
Firstly it's drawing for example: red circle in the middle of the panel, in the next frame the same circle should be moved a little to the left.
The should be motion effect as the frames change quickly. I've decided to use vector wxBitmap which is being filled by the Draw() function.
Next Repaint() function which is connected to wxTimer should draw on wxPanel single frames that last period of time which is stated in the .txt file.

Code: Select all


int increment; 

GUIMyFrame::GUIMyFrame(wxWindow *parent)
	: MyFrame(parent, wxID_ANY, "Animacje"),
	m_isMusicActived{ false },
	m_isStopActived{ false },
	m_chosenAnimation{ nic },
	//m_imageHandler{ new wxPNGHandler() },
	m_penSize{ 1 },
	m_brushColor{ wxColor(255, 255, 255) },
	m_pen{ wxPen(wxColor(0, 0, 0), m_penSize) },
	m_allAnimation{wxNullBitmap},
	m_timeFrames{ 0 },
	m_isNew{true},
	m_frame{0},
	m_numberOfFrames{0}

{
	increment = 1;
	Draw();
}

GUIMyFrame::~GUIMyFrame()
{
	
}



void GUIMyFrame::OnUpdateUI(wxUpdateUIEvent &event)
{
	Repaint();
}


void GUIMyFrame::OnChoiceAnimation(wxCommandEvent &event)
{
	m_chosenAnimation = event.GetSelection();
	m_isNew = true;
	m_numberOfFrames = 0;
	Draw();

	if (!m_isStopActived)
		m_timer.Start(10);
	else
		m_timer.Stop();
}


void GUIMyFrame::OnCheckBoxStopAnimation(wxCommandEvent &event)
{
	m_isStopActived = event.IsChecked();

	if (!m_isStopActived)
		m_timer.Start(10);
	else
		m_timer.Stop();
}

void GUIMyFrame::OnTimer(wxTimerEvent& event) 
{
	m_frame = m_frame + increment;
	if (m_frame == 0) 
		increment = 1;
	if (m_frame == 100) 
		increment = -1;
	Repaint();
}

void GUIMyFrame::Repaint() 
{	
	if (m_timer.IsRunning())
	{
		wxClientDC dc(this);
		wxBufferedDC dcBuffered(&dc);
		dcBuffered.DrawBitmap(m_allAnimation[m_frame], 0, 0, true);
	}

}



std::string returnWord(int index, std::string str)
{
	std::string word;
	int count = 0; 

	for (unsigned int i = 0; i < str.length(); i++)
	{
		if (str[i] == ' ')
		{ 
			if (str[i + 1] != ' ')
			{			
				count++;
				if (count == index)
					return word;
				word = "";
			}
		}
		else
			word += str[i];
	}
	return word;
}
 
void GUIMyFrame::Draw()
{

	switch (m_chosenAnimation)
	{

	case nic:
	{
		//
		m_nameTextFile = wxT("pierwszy.txt");
		break;
	}


	case perkusista:
	{

		m_nameTextFile = wxT("drugi.txt");
		break;
	}

	} 

	
	wxTextFile tfile;
	tfile.Open(m_nameTextFile);

	wxString sizePanel;  

	if (tfile.IsOpened())
		sizePanel = tfile.GetFirstLine();

	m_panelX = std::atoi(returnWord(1, sizePanel.ToStdString()).c_str());
	m_panelY = std::atoi(returnWord(2, sizePanel.ToStdString()).c_str());

	m_allAnimation.reserve(10);

	wxMemoryDC dcTemp;										
	wxBitmap bitmapTemp(m_panelX, m_panelY);

	dcTemp.SelectObject(bitmapTemp);
	dcTemp.SetBackground(m_brushColor);
	dcTemp.Clear();

	wxString strLine;	
	wxString word;		


	while (true)
	{
		strLine = tfile.GetNextLine();				 
		word = returnWord(1, strLine.ToStdString()); 


		
		if ( isdigit(word[0]) )
		{																			
			m_timeFrames.push_back(std::stoi(returnWord(2, strLine.ToStdString()).c_str()));
			m_numberOfFrames++;
		}

	
		if ((word == "RP") )
		{
			m_penSize = std::stoi(returnWord(2, strLine.ToStdString()));
			dcTemp.SetPen(wxPen(wxColor(0, 0, 0), m_penSize));
		}


		if ((word == "KP"))
		{
			int r, g, b;
			r = std::stoi(returnWord(2, strLine.ToStdString()));
			g = std::stoi(returnWord(3, strLine.ToStdString()));
			b = std::stoi(returnWord(4, strLine.ToStdString()));

			dcTemp.SetPen(wxPen(wxColor(r, g, b), m_penSize));
			m_pen = wxPen(wxColor(r, g, b), m_penSize);
		}


		if ((word == "KW"))
		{
			int r, g, b;
			r = std::stoi(returnWord(2, strLine.ToStdString()));
			g = std::stoi(returnWord(3, strLine.ToStdString()));
			b = std::stoi(returnWord(4, strLine.ToStdString()));

			dcTemp.SetBrush(wxBrush(wxColor(r, g, b)));
			m_brushColor = wxBrush(wxColor(r, g, b));
		}


		if ((word == "LN"))
		{
			int x1, y1, x2, y2;
			x1 = std::stoi(returnWord(2, strLine.ToStdString()));
			y1 = std::stoi(returnWord(3, strLine.ToStdString()));
			x2 = std::stoi(returnWord(4, strLine.ToStdString()));
			y2 = std::stoi(returnWord(5, strLine.ToStdString()));

			dcTemp.DrawLine(x1, y1, x2, y2);
		}

		if ((word == "PT"))
		{
			int x, y;
			x = std::stoi(returnWord(2, strLine.ToStdString()));
			y = std::stoi(returnWord(3, strLine.ToStdString()));

			dcTemp.DrawPoint(x, y);
		}

	
		if ((word == "EL"))
		{
			int x1, y1, x2, y2, flag;
			x1 = std::stoi(returnWord(2, strLine.ToStdString()));
			y1 = std::stoi(returnWord(3, strLine.ToStdString()));
			x2 = std::stoi(returnWord(4, strLine.ToStdString()));
			y2 = std::stoi(returnWord(5, strLine.ToStdString()));
			flag = std::stoi(returnWord(6, strLine.ToStdString()));

			if (flag) 
			{
				dcTemp.SetBrush(m_brushColor);
				dcTemp.DrawEllipse(x1, y1, x2, y2);
			}
			else
			{
				dcTemp.SetBrush(wxBrush(wxColor(255, 255, 255)));
				dcTemp.DrawEllipse(x1, y1, x2, y2);
				dcTemp.SetBrush(m_brushColor); 
			}
		}

		if ((word == "PR"))
		{
			int x1, y1, x2, y2, flag;
			x1 = std::stoi(returnWord(2, strLine.ToStdString()));
			y1 = std::stoi(returnWord(3, strLine.ToStdString()));
			x2 = std::stoi(returnWord(4, strLine.ToStdString()));
			y2 = std::stoi(returnWord(5, strLine.ToStdString()));
			flag = std::stoi(returnWord(6, strLine.ToStdString()));

			if (flag) 
			{
				dcTemp.SetBrush(m_brushColor);
				dcTemp.DrawRectangle(x1, y1, x2, y2);
			}
			else 
			{
				dcTemp.SetBrush(wxBrush(wxColor(255, 255, 255)));
				dcTemp.DrawRectangle(x1, y1, x2, y2);
				dcTemp.SetBrush(m_brushColor);
			}
		}


		
		if ((word == "ST") || (word == "stop"))
		{
			m_allAnimation.push_back(bitmapTemp); 
			dcTemp.Clear();
		}
		


		if (word == wxT("KONIEC") ) break;			



	} //END TXT

	m_penSize = 1;
	m_brushColor = wxColor(255, 255, 255);
	m_pen = wxPen(wxColor(0, 0, 0), m_penSize);



}
An error appears:
"failed int wxMSWDCImpl::DoDrawBitmap(): invalid bitmap in wxMSWDCImpl::DrawBitmap"
Does anyone know how to fix this error? Any help would be appreciated.

User avatar
doublemax
Moderator
Moderator
Posts: 13988
Joined: Fri Apr 21, 2006 8:03 pm
Location: $FCE2

Re: Animation i wxWidgets [wxTimer, wxTextFile]

Post by doublemax » Sat Jun 01, 2019 11:07 am

The error message speaks for itself, the bitmap you're drawing is not valid. It probably happens in this line:

Code: Select all

dcBuffered.DrawBitmap(m_allAnimation[m_frame], 0, 0, true);
Use a debugger to check if "m_frame" contains what you expect and if the vector contains a valid bitmap at this point.

This code here is a little suspicious:

Code: Select all

	m_frame = m_frame + increment;
	if (m_frame == 0) 
		increment = 1;
	if (m_frame == 100) 
		increment = -1;
This would only be valid if your animation has at least 100 frames. I think instead of "100" you should use the length of the bitmap array here.

For debugging purposes you could also write each generated bitmap to a file inside your Draw() method.

Apart from that: The way when and from where you draw the bitmap(s) is not optimal. You should have a general paint event handler that just draws the current bitmap. And in the timer event, you should just call Refresh(). Get rid of the OnUpdateUI handler.
Use the source, Luke!

Post Reply