wxWidgets : ProgressBar in StatusBar
-
Sehr geehrtes Forum, ich bin noch neu bei den wxWidgets, und arbeite gerade dieses Tutorial durch :
http://zetcode.com/tutorials/wxwidgetstutorial/ , es gibt eine Menge zu lernen, und ich komm gut voran. Ich wollte nebenbei, mit dem neuerlernten, einen kleinen Editor, "SimpleEditor", schreiben, also für .txt dateien, ganz simple sollte der sein. Und da wollte ich euch fragen, wie man eine ProgressBar in die Statusbar einfügen kann.Was ich bisher kann:
// ... irgendwo im Konstruktor einer Klasse, die wxFrame ableitet CreateStatusBar(3); // Drei Statusinformationen können angezeigt werden SetStatusText(_wxT("Text an Informationsstelle 1"),0); // Wie kann ich jetzt anstatt des Textes eine Progressbar einbauen, und // jederzeit angeben, wie weit der Progress ist? sozusagen, einen Integer-Wert //angeben, von 0 bis 100, also in Prozent.
Es gibt ja z.B. beim IE eine ProgressBar in der Statusbar unten, die anzeigt, wie stark die Seite schon geladen wurde, so eine wollte ich für mein Programm auch haben.
Danke für eure Hilfen,
Developer-X
-
Dafür musst du ein Objekt der Klasse wxStatusBar benutzen. Im wxWidgets Verzeichnis unter samples gibt es auch ein Beispiel, welches genau das machen sollte (im Ordner statbar). Leider kann ich nichts näheres dazu sagen, weil die Linux-Zeilenumbrüche nicht richtig angezeigt werden
.
-
Ich danke dir, ich werde es versuchen, falls ich es nicht kann, frage ich dich noch einmal, danke sehr,
Developer-X
-
Verzeihung, aber ich kriege das einfach nicht hin, kann mir bitte einer helfen?
Ich verstehe leider nicht wie ich eine Progress Bar in die Statusbar bekomme, geschweige denn, wie ich überhaupt eine progressbar adde, ich hoffe jemand kann mir helfen?M.f.G Developer_X
-
Minimalbeispiel für dich.........
Application.hpp:
#ifndef APPLICATION_HPP #define APPLICATION_HPP #include <wx/wx.h> enum Id { ID_TIMER = wxID_AUTO_HIGHEST + 20, }; class Application : public wxApp { public: virtual bool OnInit(); }; class Mainframe : public wxFrame { public: Mainframe(); virtual ~Mainframe(); void OnTimerEvent(wxTimerEvent& e); private: wxTimer* m_pTimer; wxGauge* m_pGauge; DECLARE_EVENT_TABLE(); }; #endif // APPLICATION_HPP
Application.cpp:
#include "Application.hpp" IMPLEMENT_APP(Application) BEGIN_EVENT_TABLE(Mainframe, wxFrame) EVT_TIMER(ID_TIMER, Mainframe::OnTimerEvent) END_EVENT_TABLE() bool Application::OnInit() { Mainframe *f = new Mainframe(); f->Show(); SetTopWindow(f); return true; } Mainframe::Mainframe() : wxFrame(NULL, wxID_ANY, "StatusBarTest") { wxStatusBar* pStatBar = this->CreateStatusBar(2); m_pGauge = new wxGauge(pStatBar, wxID_ANY, 100); m_pGauge->SetSize(150,10); m_pGauge->CenterOnParent(wxVERTICAL); m_pTimer = new wxTimer(this, ID_TIMER); if ( m_pTimer->Start(500, false) == false ) { wxMessageBox("Could not start Timer!"); } } Mainframe::~Mainframe() { delete m_pTimer; } void Mainframe::OnTimerEvent( wxTimerEvent& e ) { if ( m_pGauge ) { int value = m_pGauge->GetValue() +1; if ( value == 100 ) value = 0; m_pGauge->SetValue(value); wxString s; s << value; this->SetStatusText(s, 1); } }
Ist wie immer:
wxGauge als Child der Statusbar erzeugen ;).
Ganz einfach :D.
rya.edit: Ein wenig schöner gemacht :p
-
Ich danke dir sehr, ich habe nur eine Frage, wie kann ich entscheiden, wo die ProgressBar sein soll, ich habe eine Status-Bar mit 3 Feldern erzeugt, ich will die ProgressBar in die 2te, danke wennn du mir das noch sagen könntest,
Developer_X
-
Weil ich habe noch eine Frage:
Und zwar schreibe ich gerade ein Editor Programm. Bei der Methode laden, wollte ich eigentlich, dass man sieht, wie weit der Stand des Ladens des Textes ist, versteht ihr?wxTextCtrl hat aber die praktische Methode LoadFile und daher, wollte ich wissen, ob es möglich ist, das irgendwie zu verknüpfen.
Man kann ja mit wxGauge::SetValue(int i ) die Prozent angeben.
Was kann man das jetzt machen?
-
Was kann man da jetzt machen?
Mal die wxWidgets Dokumentation lesen..
rya.
-
wxTextCtrl::LoadFile
bool LoadFile(const wxString& filename, int fileType = wxTEXT_TYPE_ANY)Loads and displays the named file, if it exists.
Parameters
filename
The filename of the file to load.
fileTypeThe type of file to load. This is currently ignored in wxTextCtrl.
Return valuetrue if successful, false otherwise.
weiter?
-
Naja, das is nicht ganz so einfach. Du kannst ne Datei nicht als ganzes einlesen und dann nen Status verlangen. Afaik gibt LoadFile() keinen zurück wie Du ja merkst. Du müsstest also die Größe der Datei abfragen und dann beim einlesen die Anzahl der gelesenen Bytes prozentual auf der wxGauge darstellen. Aber solange man es nicht immer mit großen Dateien zu tun hat, ist das eigentlich sinnlose Liebesmühe, da kleine Dateien eigentlich schneller geladen sind als man das überhaupt mitbekommt dass da ne ProgressBar mitläuft.
rya.
-
ok, soll ja auch nur ein kleiner editor werdn
-
Altes Topic, aber wenn man gerade auf der Suche nach Performance-Problemen mit grossen Textfiles ist ...
Wie hiess die Frage nochmal? Ob man Developer_X verbieten sollte eine wxGauge zur Anzeige des Ladeprozesses zu verwenden?
Spass beiseite:Ich hab einfach die Implementation von wxTextFile genommen und mit einem Event gespickt. Das geht bei anderen
File Klassen genau so. Schöner wäre es natürlich wenn man die Read() Methode überschreiben würde. Hmmm, ich glaub das ging in dem Falle nicht so einfach, weil das m_file privat ist.Header progresstextfile.h, Events + Deklaration
/////////////////////////////////////////////////////////////////////////////// // Name: progresstextfile.h // Purpose: declaration of ProgressTextFile class // Author: Jedzia // Modified by: // Created: 11.04.2011 // Copyright: (c) 2011 Jedzia // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// #ifndef PROGRESSTEXTFILE_H #define PROGRESSTEXTFILE_H #include "wx/textbuf.h" #include "wx/file.h" #include <wx/thread.h> #include <wx/string.h> #include <wx/event.h> DECLARE_EVENT_TYPE( LoadProgressCommandEvent, -1 ) // A custom event that transports the loading progress data. class LoadProgressEvent: public wxCommandEvent { public: LoadProgressEvent( wxEventType commandType = LoadProgressCommandEvent, int id =0 ) : wxCommandEvent(commandType, id) { } // You *must* copy here the data to be transported LoadProgressEvent( const LoadProgressEvent &event ) : wxCommandEvent(event) { this->SetInt( event.GetInt() ); this->SetText( event.GetText() ); } // Required for sending with wxPostEvent() wxEvent* Clone() const { return new LoadProgressEvent(*this); } wxString GetText() const { return m_Text; } void SetText( const wxString& text ) { m_Text = text; } private: wxString m_Text; }; typedef void (wxEvtHandler::*LoadProgressEventFunction)(LoadProgressEvent &); #define LoadProgressEventHandler(func) (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction) wxStaticCastEvent(LoadProgressEventFunction, &func) #define EVT_LOAD_PROGRESS(winid, func) wx__DECLARE_EVT1(LoadProgressCommandEvent, winid, LoadProgressEventHandler(func)) #define EVT_LOAD_PROGRESS_RANGE(id1,id2, fn) wxDECLARE_EVENT_TABLE_ENTRY(LoadProgressCommandEvent, id1, id2, LoadProgressEventHandler(fn), (wxObject*)NULL ), // ---------------------------------------------------------------------------- // ProgressTextFile // ---------------------------------------------------------------------------- class WXDLLIMPEXP_BASE ProgressTextFile : public wxTextBuffer { public: enum { Loading = 1, Parsing, }; // constructors ProgressTextFile() { m_pHandler = NULL; } //ProgressTextFile(const wxString& strFileName); ProgressTextFile(const wxString& strFileName, wxEvtHandler *handler = NULL); protected: // implement the base class pure virtuals virtual bool OnExists() const; virtual bool OnOpen(const wxString &strBufferName, wxTextBufferOpenMode OpenMode); virtual bool OnClose(); virtual bool OnRead(const wxMBConv& conv); virtual bool OnWrite(wxTextFileType typeNew, const wxMBConv& conv); protected: wxEvtHandler *m_pHandler; private: wxFile m_file; wxDECLARE_NO_COPY_CLASS(ProgressTextFile); };
- Source progresstextfile.cpp, Implementation
/////////////////////////////////////////////////////////////////////////////// // Name: progresstextfile.cpp ( from wxWidgeds src/common/textfile.cpp ) // Purpose: implementation of ProgressTextFile class // Author: Vadim Zeitlin // Modified by: Jedzia 2011 // Created: 03.04.98 // RCS-ID: $Id: textfile.cpp 61508 2009-07-23 20:30:22Z VZ $ // Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr> // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// // ============================================================================ // headers // ============================================================================ #include "progresstextfile.h" // class's header file #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif //__BORLANDC__ #ifndef WX_PRECOMP #include "wx/string.h" #include "wx/intl.h" #include "wx/file.h" #include "wx/log.h" #endif #include "wx/textfile.h" #include "wx/filename.h" #include "wx/buffer.h" DEFINE_EVENT_TYPE( LoadProgressCommandEvent ) // ============================================================================ // ProgressTextFile class implementation // ============================================================================ /*ProgressTextFile::ProgressTextFile(const wxString& strFileName) : wxTextBuffer(strFileName) { m_pHandler = NULL; }*/ ProgressTextFile::ProgressTextFile(const wxString& strFileName, wxEvtHandler *handler) : wxTextBuffer(strFileName) { m_pHandler = handler; } // ---------------------------------------------------------------------------- // file operations // ---------------------------------------------------------------------------- bool ProgressTextFile::OnExists() const { return wxFile::Exists(m_strBufferName); } bool ProgressTextFile::OnOpen(const wxString &strBufferName, wxTextBufferOpenMode OpenMode) { wxFile::OpenMode FileOpenMode; switch ( OpenMode ) { default: wxFAIL_MSG( wxT("unknown open mode in ProgressTextFile::Open") ); // fall through case ReadAccess : FileOpenMode = wxFile::read; break; case WriteAccess : FileOpenMode = wxFile::write; break; } return m_file.Open(strBufferName.c_str(), FileOpenMode); } bool ProgressTextFile::OnClose() { return m_file.Close(); } bool ProgressTextFile::OnRead(const wxMBConv& conv) { int lastpercent = -1; int nxRemaining = -1; // file should be opened wxASSERT_MSG( m_file.IsOpened(), wxT("can't read closed file") ); // read the entire file in memory: this is not the most efficient thing to // do it but there is no good way to avoid it in Unicode build because if // we read the file block by block we can't convert each block to Unicode // separately (the last multibyte char in the block might be only partially // read and so the conversion would fail) and, as the file contents is kept // in memory by ProgressTextFile anyhow, it shouldn't be a big problem to read // the file entirely size_t bufSize = 0; // number of bytes to (try to) read from disk at once static const size_t BLOCK_SIZE = 4096; wxCharBuffer buf; // first determine if the file is seekable or not and so whether we can // determine its length in advance wxFileOffset fileLength; { wxLogNull logNull; fileLength = m_file.Length(); } // some non-seekable files under /proc under Linux pretend that they're // seekable but always return 0; others do return an error const bool seekable = fileLength != wxInvalidOffset && fileLength != 0; if ( seekable ) { // we know the required length, so set the buffer size in advance bufSize = fileLength; if ( !buf.extend(bufSize) ) return false; // if the file is seekable, also check that we're at its beginning wxASSERT_MSG( m_file.Tell() == 0, wxT("should be at start of file") ); char *dst = buf.data(); int lastpercent = -1; nxRemaining = bufSize; for ( size_t nRemaining = bufSize; nRemaining > 0; ) { size_t nToRead = BLOCK_SIZE; // the file size could have changed, avoid overflowing the buffer // even if it did if ( nToRead > nRemaining ) nToRead = nRemaining; ssize_t nRead = m_file.Read(dst, nToRead); if ( nRead == wxInvalidOffset ) { // read error (error message already given in wxFile::Read) return false; } if ( nRead == 0 ) { // this file can't be empty because we checked for this above // so this must be the end of file break; } dst += nRead; nRemaining -= nRead; // Event bei Ladevorgang auslösen if(m_pHandler) { int percent = 100 - ((nRemaining / (float) fileLength) * 100); if(percent > lastpercent) { //wxString bar = wxString::Format(wxT("%d bytes remaining.\n"), nRemaining); //wxString bar = wxString::Format(wxT("%d bytes remaining.\n"), percent); LoadProgressEvent event( LoadProgressCommandEvent, Loading ); event.SetInt( percent ); wxPostEvent( m_pHandler, event ); // SEND CUSTOM EVENT TO GUI MAINTHREAD wxThread::Sleep(5); lastpercent = percent; } } } wxASSERT_MSG( dst - buf.data() == (wxFileOffset)bufSize, wxT("logic error") ); } else // file is not seekable { char block[BLOCK_SIZE]; for ( ;; ) { ssize_t nRead = m_file.Read(block, WXSIZEOF(block)); if ( nRead == wxInvalidOffset ) { // read error (error message already given in wxFile::Read) return false; } if ( nRead == 0 ) { // if no bytes have been read, presumably this is a // valid-but-empty file if ( bufSize == 0 ) return true; // otherwise we've finished reading the file break; } // extend the buffer for new data if ( !buf.extend(bufSize + nRead) ) return false; // and append it to the buffer memcpy(buf.data() + bufSize, block, nRead); bufSize += nRead; } } const wxString str(buf, conv, bufSize); // there's no risk of this happening in ANSI build #if wxUSE_UNICODE if ( bufSize > 4 && str.empty() ) { wxLogError(_("Failed to convert file \"%s\" to Unicode."), GetName()); return false; } #endif // wxUSE_UNICODE // we don't need this memory any more buf.reset(); // now break the buffer in lines // last processed character, we need to know if it was a CR or not wxChar chLast = '\0'; // the beginning of the current line, changes inside the loop wxString::const_iterator lineStart = str.begin(); const wxString::const_iterator end = str.end(); int cnt = 0; lastpercent = -1; for ( wxString::const_iterator p = lineStart; p != end; p++ ) { cnt++; const wxChar ch = *p; switch ( ch ) { case '\n': // could be a DOS or Unix EOL if ( chLast == '\r' ) { if ( p - 1 >= lineStart ) { AddLine(wxString(lineStart, p - 1), wxTextFileType_Dos); } else { // there were two line endings, so add an empty line: AddLine(wxEmptyString, wxTextFileType_Dos); } } else // bare '\n', Unix style { AddLine(wxString(lineStart, p), wxTextFileType_Unix); } lineStart = p + 1; break; case '\r': if ( chLast == '\r' ) { // Mac empty line AddLine(wxEmptyString, wxTextFileType_Mac); lineStart = p + 1; } //else: we don't know what this is yet -- could be a Mac EOL or // start of DOS EOL so wait for next char break; default: if ( chLast == '\r' ) { // Mac line termination if ( p - 1 >= lineStart ) { AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); } else { // there were two line endings, so add an empty line: AddLine(wxEmptyString, wxTextFileType_Mac); } lineStart = p; } } chLast = ch; // Event beim Line Parsen auslösen if(m_pHandler) { int percent = ((cnt / (float) fileLength) * 100); if(percent > lastpercent) { //wxString bar = wxString::Format(wxT("%d bytes remaining.\n"), nRemaining); //wxString bar = wxString::Format(wxT("%d bytes remaining.\n"), percent); LoadProgressEvent event( LoadProgressCommandEvent, Loading ); event.SetInt( percent ); wxPostEvent( m_pHandler, event ); // SEND CUSTOM EVENT TO GUI MAINTHREAD lastpercent = percent; } } } // anything in the last line? if ( lineStart != end ) { // add unterminated last line AddLine(wxString(lineStart, end), wxTextFileType_None); } return true; } bool ProgressTextFile::OnWrite(wxTextFileType typeNew, const wxMBConv& conv) { wxFileName fn = m_strBufferName; // We do NOT want wxPATH_NORM_CASE here, or the case will not // be preserved. if ( !fn.IsAbsolute() ) fn.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE | wxPATH_NORM_LONG); wxTempFile fileTmp(fn.GetFullPath()); if ( !fileTmp.IsOpened() ) { wxLogError(_("can't write buffer '%s' to disk."), m_strBufferName.c_str()); return false; } size_t nCount = GetLineCount(); for ( size_t n = 0; n < nCount; n++ ) { fileTmp.Write(GetLine(n) + GetEOL(typeNew == wxTextFileType_None ? GetLineType(n) : typeNew), conv); } // replace the old file with this one return fileTmp.Commit(); }
- Verwendung z.B. in deinem Frame
Header: #include "progresstextfile.h" ... void OnIndexLoadEvent( LoadProgressEvent &event ); Source: BEGIN_EVENT_TABLE( MainForm, wxFrame ) ... EVT_THREAD(WORKER_EVENT, MainForm::OnThreadCompletion) EVT_LOAD_PROGRESS(wxID_ANY, MainForm::OnIndexLoadEvent) END_EVENT_TABLE() ... void MainForm::OnIndexLoadEvent( LoadProgressEvent &event ) { switch( event.GetId() ) { case ProgressTextFile::Loading: { int percent = event.GetInt(); wxString msg = wxString::Format(wxT("Loading %d%%.\n"), percent); statusbar->SetStatusText(msg); progressbar->SetValue(percent); } break; case ProgressTextFile::Parsing: { int percent = event.GetInt(); wxString msg = wxString::Format(wxT("Parsing %d%%.\n"), percent); statusbar->SetStatusText(msg); progressbar->SetValue(percent); } break; } }
- Das File wird dann in einem Thread in der Entry() Methode mit
wxThread::ExitCode IndexLoadThread::Entry() { ProgressTextFile * file = new ProgressTextFile(m_filename, m_pHandler); if (file->Exists()) { if(!file->Open()) { delete file; file = NULL; } } else { delete file; file = NULL; } wxThreadEvent event( wxEVT_COMMAND_THREAD, MainForm::WORKER_EVENT ); event.SetClientData (file); //event.SetInt( 50 ); wxQueueEvent( m_pHandler, event.Clone() ); return (wxThread::ExitCode)0; // success }
- geladen und an das MainForm per event zurückgegeben.
An den m_pHandler kommt man über die GetEventHandler() Methode eines Widgets ( wxEvtHandler *m_pHandler; ).
void MainForm::OnThreadCompletion(wxThreadEvent& event) { m_sf = static_cast<wxTextFile *>(event.GetClientData()); if(m_sf) { toolbar->EnableTool(ID_SEARCH, true); statusbar->SetStatusText(wxT("Index-file ") + GetSearchFileName() + wxT(" loaded. ")); } else statusbar->SetStatusText(wxT("Error while loading the index-file ") + GetSearchFileName()); }
Sieht nur so kompliziert aus, weil die wxTextFile-Implementation 1:1 übernommen wurde.
Mfg. Jed