Cross-Platform Programming with wxWidgets
Just Make It Cross-Platform
Subscribe to Feed
  • Home
  • Projects
  • Links

Posts Tagged ‘wxWidgets’

Реализация Job Queue на wxWidgets (+исходник)

Components, wxWidgets No Comments » |

При работе с потоками часто приходится делать кучу однотипных задач: создавать класс, производный от wxThread, реализовывать метод Entry() для этого класса, синхронизацию с главным потоком и т.д.

Eran, автор CodeLite IDE поделился кодом класса JobQueue, который реализует пул потоков и позволяет выполнять задачи в фоновом режиме.

class MyJob : public Job {
public:
        MyJob(){}
        ~MyJob(){}

        // Implement your processing code here
        void Process() {
                wxPrintf(wxT("Just doing my work...n"));
        };
};

// define some custom job with progress report
class MyJobWithProgress : public Job {
public:
        MyJobWithProgress(wxEvtHandler *parent) : Job(parent){}
        ~MyJobWithProgress(){}

        // Implement your processing code here
        void Process() {
                // report to parent that we are at stage 0
                Post(0, wxT("Stage Zero"));
                // do the work
                wxPrintf(wxT("Just doing my work...n"));
                // report to parent that we are at stage 1
                Post(1, wxT("Stage Zero Completed!"));
        };
};

// somewhere in your code, start the JobQueue
// for the demo we use pool of size 5
JobQueueSingleton::Instance()->Start(5);

// whenever you want to process MyJob(), just create new instance of MyJob() and add it to the JobQueue
JobQueueSingleton::Instance()->AddJob( new MyJob() );

// at shutdown stop the job queue and release all its resources
JobQueueSingleton::Instance()->Stop();
JobQueueSingleton::Release();

// OR, you can use JobQueue directly without the JobQueueSingleton wrapper class
// so you could have multiple instances of JobQueue

Главный поток получает уведомления таким вот образом:

// in the event table
EVT_COMMAND(wxID_ANY, wxEVT_CMD_JOB_STATUS, MyFrame::OnJobStatus)

void MyFrame::OnJobStatus(wxCommandEvent &e)
{
    wxString msg;
    msg << wxT("Job progress: Stage: ") << e.GetInt() << wxT(" Message: ") << e.GetString();
    wxLogMessage(msg)
}

Скачать исходный код
Читать обсуждение на wxForum


May 10th, 2008 |

Tags: Components, wxThread, wxWidgets, Статьи




wxJSON 0.4 Released

News No Comments » |

This release adds the ‘copy-on-write’ feature to the copy ctor and assignment operator of JSON value class.
Note that this new feature only affects the internal representation of JSON values and does not add new features in the class’s interface.
Also note that for JSON value objects, COW is not as efficient as expected.
To know more about this topic read this page:

The wxJSON library is now complete and this release should be considered a final beta release.
JSON data format is very stable. It is accredited to be stable forever or, at least, until programming language’s variables are based on numbers, strings, booleans, structures and arrays.

No other feature should have to be added to the library and I think that, after a few months used for discovering and fixing bugs, I will release the stable version 1.0

This will be the good occasion to, eventually, break the compatibility with the old versions 0.x by changing memberfunction’s names and/or parameters.
If you have any comment, suggestion or hint, feel free to write to me or post an answer to this topic.

Regards
Luciano

  • wxJSON website
  • wxJSON detailed documentation

April 9th, 2008 |

Tags: News, wxJSON, wxWidgets




Getting Acquainted with Document-View architecture – Part II – Simple Text Editor

wxWidgets No Comments » |

Today we’ll dig a little bit deeper into Document/View framework provided by wxWidgets and will see how to create a simple text editor using this framework.
We’ll take the source code from the previous article of this series and add some modifications. You will see below that modifications are rather simple and take almost no time.
First of all we have to make wxDocTemplate to handle desired file extensions (in our case it’s TXT).
(more…)


April 6th, 2008 |

Tags: Articles, Document/View, Tutorilas, wxWidgets, Статьи




Getting Acquainted with Document-View architecture – Part I

wxWidgets No Comments » |

A few weeks ago, working on TIFF viewer software, I realized that many developers, who use wxWidgets in their work, spend their time on implementing the functionality which already exists in wxWidgets library. Such tasks as loading/saving documents, edit/copy/paste functionality, separating the GUI from application’s logic, all of them can be performed in a far more simple way than people usually do. Why should I write the code which creates wxFileDialog, checks the current state of application, asks user if he/she wants to save the changes, shows wxFileDialog for saving document into a file and so on? Why should I do everything by hands? Life is too short for spending it to all these things ;)
But there no need to give up because there is a thing (in fact, a set of things ;) ) which allow to avoid writing tons of unnecessary code. It is wxWidgets’s Document/View framework.
It is the first article from a set of articles about such an interesting part of wxWidgets as Document/View framework.
As always, I’ll try to explain everything by an example. So, the first step will be creating a skeleton application which utilizes Document/View architecture:

DocViewTestApp.h

#ifndef _DOC_VIEW_TEST_APP_H
#define _DOC_VIEW_TEST_APP_H

#include <wx/wx.h>
#include <wx/docview.h>

class DocViewTestApp : public wxApp
{
	wxDocManager * m_DocManager;
public:
	virtual bool OnInit();
	virtual int OnExit();
};

DECLARE_APP(DocViewTestApp)

#endif

DocViewTestApp.cpp

#include "DocViewTestApp.h"
#include "DocViewTestMainFrame.h"

IMPLEMENT_APP(DocViewTestApp);

bool DocViewTestApp::OnInit()
{
	m_DocManager = new wxDocManager;
	m_DocManager->SetMaxDocsOpen(1);

	DocViewTestMainFrame * frame = new DocViewTestMainFrame(m_DocManager, NULL);
	SetTopWindow(frame);
	frame->Centre();
	frame->Show();

	return true;
}

int DocViewTestApp::OnExit()
{
	wxDELETE(m_DocManager);
	return wxApp::OnExit();
}

As you can see, the application class contains a member m_DocManager which is an object of wxDocManager class.

The wxDocManager class is part of the document/view framework supported by wxWidgets, and cooperates with the wxView, wxDocument and wxDocTemplate classes.

DocViewTestMainFrame.h

#ifndef _DOC_VIEW_TEST_MAINFRAME_H
#define _DOC_VIEW_TEST_MAINFRAME_H

#include <wx/wx.h>
#include <wx/docview.h>
#include <wx/aui/aui.h>

#define DocViewTestMainFrameTitle _("DocView Test")

class DocViewTestMainFrame : public wxDocParentFrame
{
	DECLARE_DYNAMIC_CLASS(DocViewTestMainFrame)

	wxAuiManager m_AuiManager;

	void CreateControls();
	wxMenuBar * CreateMenuBar();
public:
	DocViewTestMainFrame();
	DocViewTestMainFrame(wxDocManager * docManager, wxFrame * parent,
		wxWindowID id = wxID_ANY,
		const wxString & title = DocViewTestMainFrameTitle);
	~DocViewTestMainFrame();
	bool Create(wxDocManager * docManager, wxFrame * parent,
		wxWindowID id = wxID_ANY,
		const wxString & title = DocViewTestMainFrameTitle);

	DECLARE_EVENT_TABLE()
	void OnExit(wxCommandEvent & event);
};

#endif

DocViewTestMainFrame.cpp

#include "DocViewTestMainFrame.h"

IMPLEMENT_DYNAMIC_CLASS(DocViewTestMainFrame, wxDocParentFrame)

BEGIN_EVENT_TABLE(DocViewTestMainFrame, wxDocParentFrame)
EVT_MENU(wxID_EXIT, DocViewTestMainFrame::OnExit)
END_EVENT_TABLE()

DocViewTestMainFrame::DocViewTestMainFrame()
{
}

DocViewTestMainFrame::DocViewTestMainFrame(wxDocManager * docManager, wxFrame * parent,
	wxWindowID id, const wxString & title)
{
	Create(docManager, parent, id, title);
}

DocViewTestMainFrame::~DocViewTestMainFrame()
{
	m_AuiManager.UnInit();
}

bool DocViewTestMainFrame::Create(wxDocManager * docManager, wxFrame * parent,
	wxWindowID id, const wxString & title)
{
	bool res = wxDocParentFrame::Create(docManager, parent, id, title,
		wxDefaultPosition, wxSize(650, 450));
	if(res)
	{
		CreateControls();
	}
	return res;
}

void DocViewTestMainFrame::CreateControls()
{
	SetMenuBar(CreateMenuBar());
	m_AuiManager.SetManagedWindow(this);

	m_AuiManager.AddPane(new wxPanel(this, wxID_ANY),
		wxAuiPaneInfo().CenterPane().Name(_("Canvas")));

	m_AuiManager.Update();
}

wxMenuBar * DocViewTestMainFrame::CreateMenuBar()
{
	wxMenuBar * result = new wxMenuBar;

	wxMenu * fileMenu = new wxMenu;
	fileMenu->Append(wxID_NEW, _("New\tCtrl+N"));
	fileMenu->Append(wxID_OPEN, _("Open\tCtrl+O"));
	fileMenu->AppendSeparator();
	fileMenu->Append(wxID_SAVE, _("Save\tCtrl+S"));
	fileMenu->Append(wxID_SAVEAS, _("Save as..."));
	fileMenu->AppendSeparator();
	fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));

	wxMenu * helpMenu = new wxMenu;
	helpMenu->Append(wxID_ABOUT, _("About..."));

	result->Append(fileMenu, _("File"));
	result->Append(helpMenu, _("Help"));

	return result;
}

void DocViewTestMainFrame::OnExit(wxCommandEvent &event)
{
	Close();
}

Our main frame class is derived from wxDocParentFrame class. wxDocParentFrame provides a default top-level frame for applications which utilize Document/View architecture. It can be used ONLY FOR SDI (Single Document Interface), not MDI (Multiple Document Interface) applications. As you can see, we pass a pointer to wxDocManager object to the constructor of our main frame. Passing of wxDocManager object to the constructor is mandatory because in other way our frame will not be able to load the documents.

Now, after we finished a GUI-related part, we have to create our Document and View classes:

DocViewTestDocument.h

#ifndef _DOC_VIEW_TEST_DOCUMENT_H
#define _DOC_VIEW_TEST_DOCUMENT_H

#include <wx/wx.h>
#include <wx/docview.h>

class DocViewTestDocument : public wxDocument
{
	DECLARE_DYNAMIC_CLASS(DocViewTestDocument)
public:
	DocViewTestDocument();
};

#endif

DocViewTestDocument.cpp

#include "DocViewTestDocument.h"

IMPLEMENT_DYNAMIC_CLASS(DocViewTestDocument, wxDocument)

DocViewTestDocument::DocViewTestDocument()
{
	wxLogTrace(wxTraceMask(), wxT("DocViewTestDocument::DocViewTestDocument"));
}

DocViewTestView.h

#ifndef _DOC_VIEW_TEST_VIEW_H
#define _DOC_VIEW_TEST_VIEW_H

#include <wx/wx.h>
#include <wx/docview.h>

class DocViewTestView : public wxView
{
	DECLARE_DYNAMIC_CLASS(DocViewTestView)
public:
	DocViewTestView();

	virtual void OnDraw(wxDC* dc);
	virtual void OnUpdate(wxView *sender, wxObject *hint = (wxObject *) NULL);
    virtual bool OnClose(bool deleteWindow = true);
};

#endif

Our DocViewTestView class overrides wxView::OnDraw, wxView::OnUpdate and wxView::OnClose methods.

The default implementation calls wxDocument::Close to close the associated document. Does not delete the view. The application may wish to do some cleaning up operations in this function, if a call to wxDocument::Close succeeded

DocViewTestView.cpp

#include "DocViewTestView.h"

IMPLEMENT_DYNAMIC_CLASS(DocViewTestView, wxView)

DocViewTestView::DocViewTestView()
{
	wxLogTrace(wxTraceMask(), wxT("DocViewTestView::DocViewTestView"));
	SetFrame(wxTheApp->GetTopWindow());
}

void DocViewTestView::OnDraw(wxDC* dc)
{
	wxLogTrace(wxTraceMask(), wxT("DocViewTestView::OnDraw"));
}

void DocViewTestView::OnUpdate(wxView *sender, wxObject *hint)
{
	wxLogTrace(wxTraceMask(), wxT("DocViewTestView::OnUpdate"));
}

bool DocViewTestView::OnClose(bool deleteWindow)
{
	wxLogTrace(wxTraceMask(), wxT("DocViewTestView::OnClose"));
	if (!GetDocument()->Close())
	{
        return false;
	}

	SetFrame(NULL);
    Activate(false);
    return true;
}

As you can see, we associate a top level window of our application with each object of DocViewTestView class. After that DocViewTestView object will receive events from this frame. In fact, we can associate not only wxFrame-derived objects but any wxWindow-derived object, e.g. wxScrolledWindow or wxTextCtrl.

Note that this “frame” is not a wxFrame at all in the generic MDI implementation which uses the notebook pages instead of the frames and this is why this method returns a wxWindow and not a wxFrame.

Now, after we created Document and View classes, we have to create a document template. The wxDocTemplate class is used to model the relationship between a document class and a view class.

DocViewTestApp.cpp

#include "DocViewTestApp.h"
#include "DocViewTestMainFrame.h"
#include "DocViewTestDocument.h"
#include "DocViewTestView.h"
...
bool DocViewTestApp::OnInit()
{
	m_DocManager = new wxDocManager;
	m_DocManager->SetMaxDocsOpen(1);

	wxDocTemplate * docTemplate = new
		wxDocTemplate(m_DocManager, _("DocViewTest Document"),
		wxT("*.png;*.bmp;*.tiff;*.tif;*.jpg;*.jpeg"), wxEmptyString,
		wxT("png"), wxT("DocViewTest Doc"), wxT("DocViewTest View"),
		CLASSINFO(DocViewTestDocument), CLASSINFO(DocViewTestView));
	...
}
...

As you can see here, for each wxDocTemplate object we have to specify a wxDocManager, document name (will be displayed in the file filter list of Windows file selectors), wildcard, default directory (we left this field empry by using wxEmptyString), default file extension, document type name, view type name, document and view classes.
Now we can start the application and see how it works:

Skeleton application which uses wxWidgets Document/View Framework

Skeleton application which uses wxWidgets Document/View Framework

For the first look our application does nothing. But it is only “for the first look”. If you select File -> Open menu item, file open dialog will appear and if you select a file, then the title of our main frame will be changed, if you select File -> New menu item, the title of our main frame will be changed to the name of newly created document. Also if you select File -> Save menu item, save file dialog box will appear (but in fact, you will not be able to save the document because this behavior is not specified in our skeleton application).
Also if you perform these tasks:

  • Create new document
  • Open a file
  • Save a file
  • Create new document
  • Close the application

And then will look to “Output” window of your IDE, you will see such messages:

01:54:47: DocViewTestDocument::DocViewTestDocument
01:54:47: DocViewTestView::DocViewTestView
01:54:51: DocViewTestView::OnClose
01:54:51: DocViewTestDocument::DocViewTestDocument
01:54:51: DocViewTestView::DocViewTestView
01:54:51: DocViewTestView::OnUpdate
01:55:02: DocViewTestView::OnClose
01:55:02: DocViewTestDocument::DocViewTestDocument
01:55:02: DocViewTestView::DocViewTestView
01:55:24: DocViewTestView::OnClose

Now you can get an idea about how everything works:

  • When you execute wxID_NEW command, new document is created, then a view for this document is created
  • Then you executed wxID_OPEN command, open file dialog is displayed, after you select a file wxView::OnClose method is called, then view and document are destroyed, new document is created, then a view for this document is created, wxView::OnUpdate method is called.
  • When you exit the application wxView::OnClose method is called, then view and document are destroyed.

All wxDocument-, wxView- and wxDocTemplate-derived objects are deleted automatically when wxDocManager object is destroyed (in our application we destroy it in wxApp::OnExit method).
That is all for today. In the next article I will show how to implement simple loading/saving functionality.

Download the source code for this article.


March 29th, 2008 |

Tags: Articles, Document/View, Tutorilas, wxWidgets, Статьи




Нужна помощь в улучшении документации к библиотеке wxWidgets

News No Comments » |

wxWidgets находится в процессе работы над улучшением документации – мигрирации из текущей системы, основанной на LaTeX, в Doxygen (используя отдельный набор “интерфейсных” заголовков, вместо рабочих заголовков wxWidgets).

Разработчики wxWidgets потратили несколько месяцев на создание скриптов для автоматического преобразования документации, и уже достигли той точки, где скрипты уже не могут помочь. В Документация wxWidgets довольно обширна и файлы с документацией в новом формате требуют ручной обработки чтобы исключить ошибки, которые могли появиться в процессе автоматического преобразования.

Итак, мы нуждаемся в вашей помощи для завершения этого процесса в разумные сроки. Все подробности можно найти здесь.

Если вы заинтересованы, но вам надо информация о том, как все настроить, или если у вас есть какие-либо сомнения или вопросы, не стесняйтесь задать их здесь.

Это хорошая возможность:

  • Познакомиться с wxWidgets ближе
  • Улучшить те части документации, которые вам не очень нравились
  • Помочь сделать wxWidgets еще более конкурентоспособным инструментом разработки

March 15th, 2008 |

Tags: News, wxWidgets




Собираем IDE Code::Blocks под FreeBSD

wxWidgets No Comments » |

Сегодня вашему вниманию предлагается статья Cosm’а о том, как собрать и настроить среду разработки Code::Blocks под FreeBSD.

В этой статье я попытаюсь вам объяснить как ставить Code::Blocks в FreeBSD. Code::Blocks это кросплатформенная IDE построена с помощью wxWidgets. В моем случае установка проводилась на FreeBSD-7.0-Release-i386.
(more…)


March 12th, 2008 |

Tags: Code::Blocks, wxWidgets, Статьи




wxJSON 0.3.0 Released

News No Comments » |

JSON (JavaScript Object Notation) is a lightweight data-interchange format. It is easy for humans to read and write. It is easy for machines to parse and generate. It is based on a subset of the JavaScript Programming Language, Standard ECMA-262 3rd Edition – December 1999. JSON is a text format that is completely language independent but uses conventions that are familiar to programmers of the C-family of languages, including C, C++, C#, Java, JavaScript, Perl, Python, and many others. These properties make JSON an ideal data-interchange language.

This release adds support for Unicode.
Read more about the new features of wxJSON.


March 11th, 2008 |

Tags: News, wxJSON, wxWidgets




Быстрый способ упаковки содержимого папки в ZIP-архив

wxWidgets 2 Comments » |

В wxWidgets есть такая отличная штука, как wxDirTraverser.
Что это и с чем его едят? Официальная документация говорит нам вот что:

wxDirTraverser is an abstract interface which must be implemented by objects passed to wxDir::Traverse() function.
Как по мне, довольно странное описание %), ничего толкового мы из него не узнаем. Тогда идем смотреть описание wxDir::Traverse():
Enumerate all files and directories under the given directory recursively calling the element of the provided wxDirTraverser object for each of them.
Уже лучше, оказывается, объект wxDirTraverser вызывается для каждого найденного объекта в указанном каталоге. Поиск выполняется рекурсивно для всех подкаталогов.
Итак, чем нам может помочь эта информация. Из документации видно, что у класса wxDirTraverser есть методы, которые вызываются для каждого файла или подкаталога (соответственно OnFile() и OnDir()), в которые передается путь найденного файла или каталога. Это значит что, получая имя каждого файла, мы можем сразу же добавить этот файл в архив без необходимости получения списка всех файлов и подкаталогов в массив (как мы бы сделали при использовании wxDir::GetAllFiles()).
Как это реализовано, смотрим ниже:

Dir Travaerser:

#ifndef _WX_DIR_TRAVERSER_ZIP_H
#define _WX_DIR_TRAVERSER_ZIP_H

#include <wx/wx.h>
#include <wx/dir.h>
#include <wx/zipstrm.h>
#include <wx/filename.h>
#include <wx/wfstream.h>

class wxDirTraverserZIP : public wxDirTraverser
{
public:
	wxDirTraverserZIP(wxZipOutputStream & stream, const wxString & baseDir)
		: m_Stream(stream), m_BaseDir(baseDir) { }

	virtual wxDirTraverseResult OnFile(const wxString& filename)
	{
		do
		{
			wxFileName newFileName(filename);
			newFileName.MakeRelativeTo(m_BaseDir);
			if(!m_Stream.PutNextEntry(newFileName.GetFullPath()))
			{
				break;
			}
			wxFileInputStream in(filename);
			if(!in.IsOk())
			{
				break;
			}
			m_Stream.Write(in);
			return wxDIR_CONTINUE;
		}
		while(false);
		return wxDIR_STOP;
	}

	virtual wxDirTraverseResult OnDir(const wxString& dirname)
	{
		return wxDIR_CONTINUE;
	}

private:
	wxZipOutputStream & m_Stream;
	wxString m_BaseDir;
};

#endif

Usage:

bool PackFolder(const wxString & srcFolderName, const wxString & zipFileName)
{
	do
	{
		wxFFileOutputStream out(zipFileName);
		if(!out.IsOk()) break;
		wxCSConv conv(wxT("cp-866"));
		wxZipOutputStream zip(out, 9, conv);
		if(!zip.IsOk()) break;
		wxDirTraverserZIP traverser(zip, srcFolderName);
		wxDir srcDir(srcFolderName);
		if(srcDir.Traverse(traverser, wxEmptyString) == (size_t)-1) break;
		return true;
	}
	while(false);
	return false;
}
...
// Pack the folder
if(!PackFolder(wxT("c:\\test"), wxT("c:\\some.zip")))
{
//Handle error here
}

March 4th, 2008 |

Tags: wxWidgets, wxZipOutputStream, Статьи




Find & Replace для wxWidgets-приложений

wxWidgets No Comments » |

Эх если бы вы знали сколько редакторов не могут корректно делать поиск и замену, особенно касательно неанглийского языка…

На прикручивания поиска&замены, для своего проекта на wxWidgets я убил пару дней. И вот теперь когда это кое-как работает, хочу поделится с вами. В open source проектах не удалось найти реализацию поиска для wxTextCtrl или wxRichTextCtrl, кое-какой код удалось найти на форуме, но его работоспособность оставляла желать очень и очень лучшего. Видимо все серьозные программисты для реальных проектов используют обертки над scintill‘ой. Так что пришлось писать практически с нуля.

Итак поехали.

В меню добавляем пункты Find, Find Next, Replace и соответвующие обработчики в нашу EVENT_TABLE

  // Сообщения меню
  EVT_MENU( wxID_FIND, FlashnoteFrame::OnFindClick )
  EVT_MENU( ID_FindNext, FlashnoteFrame::OnFindNextClick )
  EVT_MENU( wxID_REPLACE, FlashnoteFrame::OnReplaceClick )

  // Сообщения специфические для стандартного диалога поиска и замены
  EVT_FIND( wxID_ANY, FlashnoteFrame::OnFind )
  EVT_FIND_NEXT( wxID_ANY, FlashnoteFrame::OnFind )
  EVT_FIND_CLOSE( wxID_ANY, FlashnoteFrame::OnFindClose )
  EVT_FIND_REPLACE( wxID_ANY, FlashnoteFrame::OnReplace )
  EVT_FIND_REPLACE_ALL( wxID_ANY, FlashnoteFrame::OnReplaceAll )

В заголовочный файл добавляем такой блок


//********* FIND AND REPLACE *****************************************

  void OnFindClick( wxCommandEvent& event );
  void OnFindNextClick( wxCommandEvent& event );
  void OnReplaceClick( wxCommandEvent& event );

  void OnFind( wxFindDialogEvent& event );
  bool OnFind( bool restart=false);
  void OnFindClose( wxFindDialogEvent& event );

  void OnReplace(wxFindDialogEvent& event);
  bool OnReplace();
  void OnReplaceAll(wxFindDialogEvent& event);

  wxFindReplaceData m_findData;
  wxFindReplaceDialog * m_findDialog;
  // Specify what kind of wxFindReplaceDialog we have for search or for replace
  bool IsReplaceDlg;
  // Don't show MessageBox when can't found text when user want
  // to ReplaceAll if at least one replace was made И не идем по кругу!
  int IsReplaceAll;

Ну и теперь пишем собственно код реализующий данную функциональность

void FlashnoteFrame::OnFindClick( wxCommandEvent& event )
{
	if ( NULL == m_findDialog )
	{
		m_findDialog = new wxFindReplaceDialog( this, &m_findData,
			_("Find"), wxFR_NOWHOLEWORD );
		m_findDialog->Centre( wxCENTRE_ON_SCREEN | wxBOTH );
		IsReplaceDlg=false;
	}

	m_Note->SetFocus();
	m_findDialog->Show( true );
}

void FlashnoteFrame::OnReplaceClick( wxCommandEvent& event )
{
	if ( NULL == m_findDialog )
	{
		m_findDialog = new wxFindReplaceDialog( this, &m_findData,
			_("Find & Replace"), wxFR_REPLACEDIALOG | wxFR_NOWHOLEWORD);
		m_findDialog->Centre( wxCENTRE_ON_SCREEN | wxBOTH );
		IsReplaceDlg=true;
	}
	m_Note->SetFocus();
	m_findDialog->Show( true );
}

void FlashnoteFrame::OnFindClose( wxFindDialogEvent& event )
{
	m_findDialog->Destroy();
	m_findDialog = NULL;
}

void FlashnoteFrame::OnFindNextClick( wxCommandEvent& event )
{
	if(m_findData.GetFindString().IsEmpty())
	{
		wxCommandEvent t;
		OnFindClick(t);
	}
	else  OnFind();
}

void FlashnoteFrame::OnFind( wxFindDialogEvent& event )
{
	OnFind();
}

// Return true if we found text - need for ReplaceALL
bool FlashnoteFrame::OnFind(bool restart)
{
	if (!IsReplaceDlg)
	{	// Only for FIND dlg
		bool HideFindDialogAfterFirstFing=true;
		if (HideFindDialogAfterFirstFing && m_findDialog)
		{  // only if user want and our dlg is alive
			wxFindDialogEvent t;
			OnFindClose(t);
			m_Note->SetFocus();
		}
	}

	wxString find = m_findData.GetFindString();

	int flags = m_findData.GetFlags();
	bool forward(flags & wxFR_DOWN);

	int LastPosition=m_Note->GetLastPosition();
	long m_foundPos, StartFromBack, StartFromForward;

	if (restart)
	{
		StartFromForward=0; StartFromBack=LastPosition;
	}
	else
	{ // First time
		m_Note->GetSelection(&StartFromBack, &StartFromForward);

		// If we have not selection, wxTextCtrl return
		// StartFromBack=StartFromForward=Current_Insertion_Point,
		// but wxRichTextCtrl return -2,-2
		if (StartFromBack<0) StartFromBack=StartFromForward=m_Note->GetInsertionPoint();

		// Some optimization
		if (IsReplaceAll==0)
		{
			if (forward && (StartFromForward==LastPosition)) StartFromForward=0;
			if (!forward && (StartFromBack==0)) StartFromBack=LastPosition;

			// если первый раз ищем вперед с первой позиции или назад с
			// последней - то незачем второй раз проходить
			if ( (forward && (StartFromForward==0)) ||
				( !forward && (StartFromBack==LastPosition)) ) restart=true;
		}
		// End of Some optimization
	}

	wxString string = forward ?
		m_Note->GetRange(StartFromForward, LastPosition) :
	m_Note->GetRange(0, StartFromBack);

	if (flags & wxFR_MATCHCASE)
		m_foundPos = forward ? string.find(find) : string.rfind(find);
	else
	{
		wxString string_lwr(string), find_lwr(find);
		BegUtils::StrMakeLowerUniversal(string_lwr);
		BegUtils::StrMakeLowerUniversal(find_lwr);
		m_foundPos = forward ?
			string_lwr.find(find_lwr) :
		string_lwr.rfind(find_lwr);

		//m_foundPos = forward ?
		//string.Lower().find(find.Lower()) :
		//string.Lower().rfind(find.Lower());
	}

	// Начинаем с начала (конца) если не нашли и сюда зашли первый раз
	// (restart==false) И это не заменить все
	if (m_foundPos==-1)
	{
		if (restart || (IsReplaceAll>0))
		{  // уже по второму разу прошли или зашли из ReplaceAll
			if (IsReplaceAll<2)
				wxMessageBox(wxString::Format(
				_("Cannot find \"%s\""), find), wxT("Flashnote"),
				wxOK|wxICON_INFORMATION, m_findDialog);
			return false; //Not found
		}
		else
			return OnFind(true);  // Ищем с начала и возвращяем нашли или нет
	}

	long startPos = forward ? StartFromForward + m_foundPos : m_foundPos;
	long endPos = startPos + find.length();

	m_Note->SetSelection(startPos, endPos);
	return true;
}

void FlashnoteFrame::OnReplace(wxFindDialogEvent& event)
{
	OnReplace();
}
bool FlashnoteFrame::OnReplace()
{

	wxString FindText(m_findData.GetFindString());
	wxString SelText(m_Note->GetStringSelection());

	if (!SelText.IsEmpty())
	{ // We have selected text, if is it equal our FindText - replace it

		//		bool IsTextToReplace = m_findData.GetFlags() &
		//			wxFR_MATCHCASE ? SelText==FindText :
		//			SelText.Lower()==FindText.Lower();
		//		if (IsTextToReplace) m_Note->WriteText(m_findData.GetReplaceString());

		if (! (m_findData.GetFlags() & wxFR_MATCHCASE))
		{
			BegUtils::StrMakeLowerUniversal(SelText);
			BegUtils::StrMakeLowerUniversal(FindText);
		}

		if (SelText==FindText)
		{
			// this line is needed only for wxRichTextCtrl and needed not for wxTextCtrl
			m_Note->DeleteSelection();
			m_Note->WriteText(m_findData.GetReplaceString());
		}
	}
	return OnFind();

}
void FlashnoteFrame::OnReplaceAll(wxFindDialogEvent& event)
{
	//Note: We can't just use wxString::Replace() for
	//replace, if we have handle wxFR_MATCHCASE flag
	IsReplaceAll=1; // start ReplaceAll
	while (OnReplace()) ++IsReplaceAll; 

	if (IsReplaceAll>1)  // we have replaced something
		wxMessageBox(wxString::Format(_("Total Replacement: %i"),
		IsReplaceAll-1), wxT("Flashnote"),
		wxOK|wxICON_INFORMATION, m_findDialog);

	IsReplaceAll=0; // stop ReplaceAll
}

Основная работа идет в функции OnFind(bool restart/*=false*/) и OnReplace(), все остальное фактически обвязка вокруг этих двух функций.

Код взят из реального приложения – программы для быстрых заметок (будет использоватся с v3.0) и отражает мое субьективное представление как должен вести себя диалог вставки замены. Из плюсов – неплохо оттестирован, с учетом мелочей, но если найдете проблемы – велком в комментарии.

Особенности:

  • Поиск идет циклически по кругу, то есть по достижению конца (начала) документа, автоматически переходит на начало (конец) и продолжает поиск.
  • Замена в ручном режиме ведет себя точно также, в режиме Replace ALL документ просматривается только до конца.
  • После нахождения первого вхождения искомой строки диалог поиска скрывается, дальнейший поиск идет с использованием F3 (шоткат для меню Find Next). Изменить это можно изменив строчку bool HideFindDialogAfterFirstFing=true; в функции OnFind(bool restart/*=false*/)
  • Для приведения строки к нижнему регистру используется самописная функция StrMakeLowerUniversal() (см. ниже). При использовании стандартной Lower() регистронезависимый поиск будет работать только для латиницы.

Функция StrMakeLowerUniversal(wxString & data) преобразует строку к нижнему регистру, работая со строками на любом языке, в отличии от Lower() которая понимает только латиницу. Из минусов – поддержка только MSW.

void BegUtils::StrMakeLowerUniversal(wxString & data)
{
#ifdef __WIN32__
int len=data.length()+1;
wxChar * buf = new wxChar[len];
wxStrcpy(buf, data.c_str());
CharLower(buf);
data=buf;
delete [] buf;
#else
data.MakeLower();
#endif

Успехов в написании безглючных приложений:)

Об авторе: Тюшков Николай, автор программы для мгновенной вставки текста и ряда других программ. Так же я веду несколько авторских блогов, в частности блог мысли про wx-widgets по-русски.


February 1st, 2008 |

Tags: wxWidgets, Статьи




Собираем сторонние компоненты wxWidgets в Code::Blocks

wxWidgets No Comments » |

Сегодня я расскажу о том, как создать проект Code::Blocks, использующий в своей работе сторонние библиотеки. В качестве сторонней библиотеки мы возьмем библиотеку wxPropertyGrid, предоставляющую возможность встроить редактор свойств в приложение.

Для того, чтобы проверить как все работает, нам необходимо создать тестовое приложение, которое будет использовать в своей работе дополнительную библиотеку. Тестовое приложение я собирал с настройками, указанными ниже:

Исходный код тестового приложения:

#include <wx/wx.h>
#include <wx/propgrid/propgrid.h>

class wxTestApp : public wxApp
{
    virtual bool OnInit();
};

DECLARE_APP(wxTestApp)

class wxTestMainFrame : public wxFrame
{
    void CreateControls()
    {
        wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL);
        SetSizer(sizer);
        wxPropertyGrid * propgrid = new wxPropertyGrid(this, wxNewId(),
wxDefaultPosition, wxDefaultSize, 0);
        sizer->Add(propgrid, 1, wxEXPAND);
    }
public:
    wxTestMainFrame()
    {
        Create(NULL);
    }
    bool Create(wxWindow * parent, wxWindowID id = wxID_ANY, const wxString & title = wxT("wxTest"))
    {
        bool res = wxFrame::Create(parent, id, title);
        if(res)
        {
            CreateControls();
        }
        return res;
    }
};

bool wxTestApp::OnInit()
{
    wxTestMainFrame * frame = new wxTestMainFrame();
    SetTopWindow(frame);
    frame->Centre();
    frame->Show();
    return true;
}

IMPLEMENT_APP(wxTestApp)

После того, как мы создали тестовое приложение, нам необходимо добавить библиотеку wxPropertyGrid в workspace. wxPropertyGrid распространяется в виде архива с исходным кодом, который мы распакуем в подкаталог propgrid. Далее в Code::Blocks создаем новый проект статической библиотеки:


Нам необходимо чтобы файл проекта был создан в папке propgrid/build, поэтому этот параметр необходимо подправить вручную:


Изменяем параметры таким образом чтобы наша бибилиотека создавалась в каталоге propgrid/lib (чего-то мне показалось, что параметр Output dir в текущей версии Code::Blocks не работает):


Далее идем в настройки проекта и видим, что в Output filename у нас записано немного не то, что мы указывали при создании проекта, а именно, файл библиотеки с текущими параметрами будет создаваться в каталоге propgrid/build (в каталоге с проектом). Изменяем параметр Output filename и указываем новый путь вывода статической библиотеки:


Теперь нам необходимо указать, в какой папке наш проект статической библиотеки будет искать заголовочные файлы. Пути к заголовочным файлам необходимо указать в настройках общих для обеих сборок (Debug и Release):


Для того, чтобы проект библиотеки был собран с такими же настройками как и наше тестовое приложение (это требование обязательно), нам необходимо скопировать список директив компилятора из проекта приложения в проект библиотеки:


Далее проставляем зависимости:


Добавляем в список каталогов для поиска заголовочных файлов каталог с заголовочными файлами wxPopertyGrid:


В список каталогов для поиска библиотек добавляем путь к папке со статической библиотекой wxPropertyGrid:


В настройках линкера в список зависимостей добавляем статическую библиотеку wxPropertyGrid:


Вот и все, можно собирать проект. После сборки получим приблизительно такой результат:

Скачать пример


January 24th, 2008 |

Tags: Code::Blocks, wxPropertyGrid, wxWidgets, Статьи




Page 4 of 8« First...«23456»...Last »
  • This blog is about…

    Articles Code::Blocks Components Controls Database DatabaseLayer Document/View Eclipse Localization NetBeans Networking News Printing Reports SQLite Tutorilas Video Visual Studio wxAUI wxButton wxDev-CPP wxGrid wxHelpController wxJavaScript wxJSON wxLocale wxLog wxPaintDC wxPropertyGrid wxRuby wxSQLite3 wxThread wxValidator wxWidgets wxWinCE wxZipInputStream wxZipOutputStream XML Библиотека Книги Статьи
  • Showcase

    Visit wxToolBox Homepage

    Buy wxToolBox (with source code)

  • Archives

    • November 2009
    • September 2009
    • August 2009
    • May 2009
    • April 2009
    • March 2009
    • February 2009
    • January 2009
    • December 2008
    • September 2008
    • August 2008
    • July 2008
    • June 2008
    • May 2008
    • April 2008
    • March 2008
    • February 2008
    • January 2008
    • December 2007
    • June 2007
    • May 2007
    • January 2007
  • Recent Comments

    • T-Rex on Getting Acquainted with Document/View Framework – Simple Image Viewer
    • T-Rex on Сделайте мне красиво – Часть II – wxAUI в Multi-View приложений
    • Mardiko on Getting Acquainted with Document/View Framework – Simple Image Viewer
    • marty on Сделайте мне красиво – Часть II – wxAUI в Multi-View приложений
    • T-Rex on Перевод книги Julian’а Smart’а – Глава VI – Обработка данных с устройств ввода
  • Buttons

    Locations of visitors to this page

    Rambler's Top100
    Рейтинг@Mail.ru

Copyright © 2010 Cross-Platform Programming with wxWidgets All Rights Reserved
RSS Log in