chiark / gitweb /
Merge branch 'SteamEngine' of github.com:daid/Cura into SteamEngine
[cura.git] / Cura / gui / printWindow2.py
1 __copyright__ = "Copyright (C) 2013 David Braam - Released under terms of the AGPLv3 License"
2
3 import wx
4 import power
5 import time
6
7 from wx.lib import buttons
8
9 from Cura.util import profile
10 from Cura.util import resources
11
12 class printWindow(wx.Frame):
13         "Main user interface window"
14
15         def __init__(self, printerConnection):
16                 super(printWindow, self).__init__(None, -1, title=_("Printing"))
17                 self._printerConnection = printerConnection
18                 self.lastUpdateTime = 0
19
20                 self.SetSizer(wx.BoxSizer())
21                 self.panel = wx.Panel(self)
22                 self.GetSizer().Add(self.panel, 1, flag=wx.EXPAND)
23                 self.sizer = wx.GridBagSizer(2, 2)
24                 self.panel.SetSizer(self.sizer)
25
26                 sb = wx.StaticBox(self.panel, label=_("Statistics"))
27                 boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
28
29                 self.powerWarningText = wx.StaticText(parent=self.panel,
30                         id=-1,
31                         label=_("Your computer is running on battery power.\nConnect your computer to AC power or your print might not finish."),
32                         style=wx.ALIGN_CENTER)
33                 self.powerWarningText.SetBackgroundColour('red')
34                 self.powerWarningText.SetForegroundColour('white')
35                 boxsizer.AddF(self.powerWarningText, flags=wx.SizerFlags().Expand().Border(wx.BOTTOM, 10))
36                 self.powerManagement = power.PowerManagement()
37                 self.powerWarningTimer = wx.Timer(self)
38                 self.Bind(wx.EVT_TIMER, self.OnPowerWarningChange, self.powerWarningTimer)
39                 self.OnPowerWarningChange(None)
40                 self.powerWarningTimer.Start(10000)
41
42                 self.statsText = wx.StaticText(self.panel, -1, _("Filament: ####.##m #.##g\nEstimated print time: #####:##\nMachine state:\nDetecting baudrateXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"))
43                 boxsizer.Add(self.statsText, flag=wx.LEFT, border=5)
44
45                 self.sizer.Add(boxsizer, pos=(0, 0), span=(7, 1), flag=wx.EXPAND)
46
47                 self.connectButton = wx.Button(self.panel, -1, _("Connect"))
48                 #self.loadButton = wx.Button(self.panel, -1, 'Load')
49                 self.printButton = wx.Button(self.panel, -1, _("Print"))
50                 self.pauseButton = wx.Button(self.panel, -1, _("Pause"))
51                 self.cancelButton = wx.Button(self.panel, -1, _("Cancel print"))
52                 self.errorLogButton = wx.Button(self.panel, -1, _("Error log"))
53                 self.progress = wx.Gauge(self.panel, -1, range=1000)
54
55                 self.sizer.Add(self.connectButton, pos=(1, 1), flag=wx.EXPAND)
56                 #self.sizer.Add(self.loadButton, pos=(1,1), flag=wx.EXPAND)
57                 self.sizer.Add(self.printButton, pos=(2, 1), flag=wx.EXPAND)
58                 self.sizer.Add(self.pauseButton, pos=(3, 1), flag=wx.EXPAND)
59                 self.sizer.Add(self.cancelButton, pos=(4, 1), flag=wx.EXPAND)
60                 self.sizer.Add(self.errorLogButton, pos=(5, 1), flag=wx.EXPAND)
61                 self.sizer.Add(self.progress, pos=(7, 0), span=(1, 7), flag=wx.EXPAND)
62
63                 nb = wx.Notebook(self.panel)
64                 self.tabs = nb
65                 self.sizer.Add(nb, pos=(0, 2), span=(7, 4), flag=wx.EXPAND)
66
67                 self.temperaturePanel = wx.Panel(nb)
68                 sizer = wx.GridBagSizer(2, 2)
69                 self.temperaturePanel.SetSizer(sizer)
70
71                 self.temperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
72                 self.temperatureSelect.SetRange(0, 400)
73                 self.temperatureHeatUp = wx.Button(self.temperaturePanel, -1, str(int(profile.getProfileSettingFloat('print_temperature'))) + 'C')
74                 self.bedTemperatureLabel = wx.StaticText(self.temperaturePanel, -1, _("BedTemp:"))
75                 self.bedTemperatureSelect = wx.SpinCtrl(self.temperaturePanel, -1, '0', size=(21 * 3, 21), style=wx.SP_ARROW_KEYS)
76                 self.bedTemperatureSelect.SetRange(0, 400)
77                 self.bedTemperatureLabel.Show(False)
78                 self.bedTemperatureSelect.Show(False)
79
80                 self.temperatureGraph = TemperatureGraph(self.temperaturePanel)
81
82                 sizer.Add(wx.StaticText(self.temperaturePanel, -1, _("Temp:")), pos=(0, 0))
83                 sizer.Add(self.temperatureSelect, pos=(0, 1))
84                 sizer.Add(self.temperatureHeatUp, pos=(0, 2))
85                 sizer.Add(self.bedTemperatureLabel, pos=(1, 0))
86                 sizer.Add(self.bedTemperatureSelect, pos=(1, 1))
87                 sizer.Add(self.temperatureGraph, pos=(2, 0), span=(1, 3), flag=wx.EXPAND)
88                 sizer.AddGrowableRow(2)
89                 sizer.AddGrowableCol(2)
90
91                 nb.AddPage(self.temperaturePanel, 'Temp')
92
93                 self.directControlPanel = wx.Panel(nb)
94
95                 sizer = wx.GridBagSizer(2, 2)
96                 self.directControlPanel.SetSizer(sizer)
97                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Y100 F6000', 'G90'], 'print-move-y100.png'), pos=(0, 3))
98                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Y10 F6000', 'G90'], 'print-move-y10.png'), pos=(1, 3))
99                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Y1 F6000', 'G90'], 'print-move-y1.png'), pos=(2, 3))
100
101                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Y-1 F6000', 'G90'], 'print-move-y-1.png'), pos=(4, 3))
102                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Y-10 F6000', 'G90'], 'print-move-y-10.png'), pos=(5, 3))
103                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Y-100 F6000', 'G90'], 'print-move-y-100.png'), pos=(6, 3))
104
105                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 X-100 F6000', 'G90'], 'print-move-x-100.png'), pos=(3, 0))
106                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 X-10 F6000', 'G90'], 'print-move-x-10.png'), pos=(3, 1))
107                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 X-1 F6000', 'G90'], 'print-move-x-1.png'), pos=(3, 2))
108
109                 sizer.Add(PrintCommandButton(self, ['G28 X0 Y0'], 'print-move-home.png'), pos=(3, 3))
110
111                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 X1 F6000', 'G90'], 'print-move-x1.png'), pos=(3, 4))
112                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 X10 F6000', 'G90'], 'print-move-x10.png'), pos=(3, 5))
113                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 X100 F6000', 'G90'], 'print-move-x100.png'), pos=(3, 6))
114
115                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z10 F200', 'G90'], 'print-move-z10.png'), pos=(0, 8))
116                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z1 F200', 'G90'], 'print-move-z1.png'), pos=(1, 8))
117                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z0.1 F200', 'G90'], 'print-move-z0.1.png'), pos=(2, 8))
118
119                 sizer.Add(PrintCommandButton(self, ['G28 Z0'], 'print-move-home.png'), pos=(3, 8))
120
121                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z-0.1 F200', 'G90'], 'print-move-z-0.1.png'), pos=(4, 8))
122                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z-1 F200', 'G90'], 'print-move-z-1.png'), pos=(5, 8))
123                 sizer.Add(PrintCommandButton(self, ['G91', 'G1 Z-10 F200', 'G90'], 'print-move-z-10.png'), pos=(6, 8))
124
125                 sizer.Add(PrintCommandButton(self, ['G92 E0', 'G1 E2 F120'], 'extrude.png', size=(60, 20)), pos=(1, 10), span=(1, 3), flag=wx.EXPAND)
126                 sizer.Add(PrintCommandButton(self, ['G92 E0', 'G1 E-2 F120'], 'retract.png', size=(60, 20)), pos=(2, 10), span=(1, 3), flag=wx.EXPAND)
127
128                 nb.AddPage(self.directControlPanel, _("Jog"))
129
130                 self.termPanel = wx.Panel(nb)
131                 sizer = wx.GridBagSizer(2, 2)
132                 self.termPanel.SetSizer(sizer)
133
134                 f = wx.Font(8, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False)
135                 self.termLog = wx.TextCtrl(self.termPanel, style=wx.TE_MULTILINE | wx.TE_DONTWRAP)
136                 self.termLog.SetFont(f)
137                 self.termLog.SetEditable(0)
138                 self.termInput = wx.TextCtrl(self.termPanel, style=wx.TE_PROCESS_ENTER)
139                 self.termInput.SetFont(f)
140                 self._termHistory = []
141                 self._termHistoryIdx = 0
142
143                 sizer.Add(self.termLog, pos=(0, 0), flag=wx.EXPAND)
144                 sizer.Add(self.termInput, pos=(1, 0), flag=wx.EXPAND)
145                 sizer.AddGrowableCol(0)
146                 sizer.AddGrowableRow(0)
147
148                 nb.AddPage(self.termPanel, _("Term"))
149
150                 self.sizer.AddGrowableRow(6)
151                 self.sizer.AddGrowableCol(3)
152
153                 self.Bind(wx.EVT_CLOSE, self.OnClose)
154                 self.connectButton.Bind(wx.EVT_BUTTON, self.OnConnect)
155                 #self.loadButton.Bind(wx.EVT_BUTTON, self.OnLoad)
156                 self.printButton.Bind(wx.EVT_BUTTON, self.OnPrint)
157                 self.pauseButton.Bind(wx.EVT_BUTTON, self.OnPause)
158                 self.cancelButton.Bind(wx.EVT_BUTTON, self.OnCancel)
159                 self.errorLogButton.Bind(wx.EVT_BUTTON, self.OnErrorLog)
160
161                 self.Bind(wx.EVT_BUTTON, lambda e: (self.temperatureSelect.SetValue(int(profile.getProfileSettingFloat('print_temperature'))), self.machineCom.sendCommand("M104 S%d" % (int(profile.getProfileSettingFloat('print_temperature'))))), self.temperatureHeatUp)
162                 self.Bind(wx.EVT_SPINCTRL, self.OnTempChange, self.temperatureSelect)
163                 self.Bind(wx.EVT_SPINCTRL, self.OnBedTempChange, self.bedTemperatureSelect)
164
165                 self.Bind(wx.EVT_TEXT_ENTER, self.OnTermEnterLine, self.termInput)
166                 self.termInput.Bind(wx.EVT_CHAR, self.OnTermKey)
167
168                 self.Layout()
169                 self.Fit()
170                 self.Centre()
171
172                 self.statsText.SetMinSize(self.statsText.GetSize())
173                 self.statsText.SetLabel(self._printerConnection.getStatusString())
174
175                 self.UpdateButtonStates()
176
177                 self._printerConnection.addCallback(self._doPrinterConnectionUpdate)
178
179         def OnPowerWarningChange(self, e):
180                 type = self.powerManagement.get_providing_power_source_type()
181                 if type == power.POWER_TYPE_AC and self.powerWarningText.IsShown():
182                         self.powerWarningText.Hide()
183                         self.panel.Layout()
184                         self.Layout()
185                 elif type != power.POWER_TYPE_AC and not self.powerWarningText.IsShown():
186                         self.powerWarningText.Show()
187                         self.panel.Layout()
188                         self.Layout()
189
190         def OnClose(self, e):
191                 self._printerConnection.closeActiveConnection()
192                 self._printerConnection.removeCallback(self._doPrinterConnectionUpdate)
193                 self.Destroy()
194
195         def OnConnect(self, e):
196                 self._printerConnection.openActiveConnection()
197
198         def OnLoad(self, e):
199                 pass
200
201         def OnPrint(self, e):
202                 self._printerConnection.startPrint()
203
204         def OnCancel(self, e):
205                 self._printerConnection.cancelPrint()
206
207         def OnPause(self, e):
208                 self._printerConnection.pause(not self._printerConnection.isPaused())
209
210         def OnErrorLog(self, e):
211                 LogWindow(self._printerConnection.getErrorLog())
212
213         def OnTempChange(self, e):
214                 if not self._printerConnection.isAbleToSendDirectCommand():
215                         return
216                 self._printerConnection.sendCommand("M104 S%d" % (self.temperatureSelect.GetValue()))
217
218         def OnBedTempChange(self, e):
219                 if not self._printerConnection.isAbleToSendDirectCommand():
220                         return
221                 self._printerConnection.sendCommand("M140 S%d" % (self.bedTemperatureSelect.GetValue()))
222
223         def OnTermEnterLine(self, e):
224                 if not self._printerConnection.isAbleToSendDirectCommand():
225                         return
226                 line = self.termInput.GetValue()
227                 if line == '':
228                         return
229                 self._addTermLog('>%s\n' % (line))
230                 self._printerConnection.sendCommand(line)
231                 self._termHistory.append(line)
232                 self._termHistoryIdx = len(self._termHistory)
233                 self.termInput.SetValue('')
234
235         def OnTermKey(self, e):
236                 if len(self._termHistory) > 0:
237                         if e.GetKeyCode() == wx.WXK_UP:
238                                 self._termHistoryIdx -= 1
239                                 if self._termHistoryIdx < 0:
240                                         self._termHistoryIdx = len(self._termHistory) - 1
241                                 self.termInput.SetValue(self._termHistory[self._termHistoryIdx])
242                         if e.GetKeyCode() == wx.WXK_DOWN:
243                                 self._termHistoryIdx -= 1
244                                 if self._termHistoryIdx >= len(self._termHistory):
245                                         self._termHistoryIdx = 0
246                                 self.termInput.SetValue(self._termHistory[self._termHistoryIdx])
247                 e.Skip()
248
249         def _addTermLog(self, line):
250                 if len(self.termLog.GetValue()) > 10000:
251                         self.termLog.SetValue(self.termLog.GetValue()[-10000:])
252                 self.termLog.SetInsertionPointEnd()
253                 self.termLog.AppendText(line.encode('utf-8', 'replace'))
254
255         def _doPrinterConnectionUpdate(self, connection, extraInfo = None):
256                 wx.CallAfter(self.__doPrinterConnectionUpdate, connection, extraInfo)
257                 temp = [connection.getTemperature(0)]
258                 self.temperatureGraph.addPoint(temp, [0], connection.getBedTemperature(), 0)
259
260         def __doPrinterConnectionUpdate(self, connection, extraInfo):
261                 t = time.time()
262                 if self.lastUpdateTime + 0.5 > t:
263                         return
264                 self.lastUpdateTime = t
265
266                 self.UpdateButtonStates()
267                 if connection.isPrinting():
268                         self.progress.SetValue(connection.getPrintProgress() * 1000)
269                 else:
270                         self.progress.SetValue(0)
271                 self.statsText.SetLabel(connection.getStatusString())
272
273         def UpdateButtonStates(self):
274                 self.connectButton.Show(self._printerConnection.hasActiveConnection())
275                 self.connectButton.Enable(not self._printerConnection.isActiveConnectionOpen())
276                 self.pauseButton.Show(self._printerConnection.hasPause())
277                 if not self._printerConnection.hasActiveConnection() or self._printerConnection.isActiveConnectionOpen():
278                         self.printButton.Enable(not self._printerConnection.isPrinting())
279                         self.pauseButton.Enable(self._printerConnection.isPrinting())
280                         self.cancelButton.Enable(self._printerConnection.isPrinting())
281                 else:
282                         self.printButton.Enable(False)
283                         self.pauseButton.Enable(False)
284                         self.cancelButton.Enable(False)
285                 self.errorLogButton.Show(self._printerConnection.isInErrorState())
286
287                 self.directControlPanel.Enable(self._printerConnection.isAbleToSendDirectCommand())
288                 self.temperatureSelect.Enable(self._printerConnection.isAbleToSendDirectCommand())
289                 self.temperatureHeatUp.Enable(self._printerConnection.isAbleToSendDirectCommand())
290                 self.termInput.Enable(self._printerConnection.isAbleToSendDirectCommand())
291
292 class PrintCommandButton(buttons.GenBitmapButton):
293         def __init__(self, parent, commandList, bitmapFilename, size=(20, 20)):
294                 self.bitmap = wx.Bitmap(resources.getPathForImage(bitmapFilename))
295                 super(PrintCommandButton, self).__init__(parent.directControlPanel, -1, self.bitmap, size=size)
296
297                 self.commandList = commandList
298                 self.parent = parent
299
300                 self.SetBezelWidth(1)
301                 self.SetUseFocusIndicator(False)
302
303                 self.Bind(wx.EVT_BUTTON, self.OnClick)
304
305         def OnClick(self, e):
306                 if self.parent._printerConnection is None or self.parent._printerConnection.isAbleToSendDirectCommand():
307                         return
308                 for cmd in self.commandList:
309                         self.parent._printerConnection.sendCommand(cmd)
310                 e.Skip()
311
312 class TemperatureGraph(wx.Panel):
313         def __init__(self, parent):
314                 super(TemperatureGraph, self).__init__(parent)
315
316                 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
317                 self.Bind(wx.EVT_SIZE, self.OnSize)
318                 self.Bind(wx.EVT_PAINT, self.OnDraw)
319
320                 self._lastDraw = time.time() - 1.0
321                 self._points = []
322                 self._backBuffer = None
323                 self.addPoint([0]*16, [0]*16, 0, 0)
324                 self.SetMinSize((320, 200))
325
326         def OnEraseBackground(self, e):
327                 pass
328
329         def OnSize(self, e):
330                 if self._backBuffer is None or self.GetSize() != self._backBuffer.GetSize():
331                         self._backBuffer = wx.EmptyBitmap(*self.GetSizeTuple())
332                         self.UpdateDrawing(True)
333
334         def OnDraw(self, e):
335                 dc = wx.BufferedPaintDC(self, self._backBuffer)
336
337         def UpdateDrawing(self, force=False):
338                 now = time.time()
339                 if (not force and now - self._lastDraw < 1.0) or self._backBuffer is None:
340                         return
341                 self._lastDraw = now
342                 dc = wx.MemoryDC()
343                 dc.SelectObject(self._backBuffer)
344                 dc.Clear()
345                 dc.SetFont(wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT))
346                 w, h = self.GetSizeTuple()
347                 bgLinePen = wx.Pen('#A0A0A0')
348                 tempPen = wx.Pen('#FF4040')
349                 tempSPPen = wx.Pen('#FFA0A0')
350                 tempPenBG = wx.Pen('#FFD0D0')
351                 bedTempPen = wx.Pen('#4040FF')
352                 bedTempSPPen = wx.Pen('#A0A0FF')
353                 bedTempPenBG = wx.Pen('#D0D0FF')
354
355                 #Draw the background up to the current temperatures.
356                 x0 = 0
357                 t0 = [0] * len(self._points[0][0])
358                 bt0 = 0
359                 tSP0 = 0
360                 btSP0 = 0
361                 for temp, tempSP, bedTemp, bedTempSP, t in self._points:
362                         x1 = int(w - (now - t))
363                         for x in xrange(x0, x1 + 1):
364                                 for n in xrange(0, len(temp)):
365                                         t = float(x - x0) / float(x1 - x0 + 1) * (temp[n] - t0[n]) + t0[n]
366                                         dc.SetPen(tempPenBG)
367                                         dc.DrawLine(x, h, x, h - (t * h / 300))
368                                 bt = float(x - x0) / float(x1 - x0 + 1) * (bedTemp - bt0) + bt0
369                                 dc.SetPen(bedTempPenBG)
370                                 dc.DrawLine(x, h, x, h - (bt * h / 300))
371                         t0 = temp
372                         bt0 = bedTemp
373                         tSP0 = tempSP
374                         btSP0 = bedTempSP
375                         x0 = x1 + 1
376
377                 #Draw the grid
378                 for x in xrange(w, 0, -30):
379                         dc.SetPen(bgLinePen)
380                         dc.DrawLine(x, 0, x, h)
381                 tmpNr = 0
382                 for y in xrange(h - 1, 0, -h * 50 / 300):
383                         dc.SetPen(bgLinePen)
384                         dc.DrawLine(0, y, w, y)
385                         dc.DrawText(str(tmpNr), 0, y - dc.GetFont().GetPixelSize().GetHeight())
386                         tmpNr += 50
387                 dc.DrawLine(0, 0, w, 0)
388                 dc.DrawLine(0, 0, 0, h)
389
390                 #Draw the main lines
391                 x0 = 0
392                 t0 = [0] * len(self._points[0][0])
393                 bt0 = 0
394                 tSP0 = [0] * len(self._points[0][0])
395                 btSP0 = 0
396                 for temp, tempSP, bedTemp, bedTempSP, t in self._points:
397                         x1 = int(w - (now - t))
398                         for x in xrange(x0, x1 + 1):
399                                 for n in xrange(0, len(temp)):
400                                         t = float(x - x0) / float(x1 - x0 + 1) * (temp[n] - t0[n]) + t0[n]
401                                         tSP = float(x - x0) / float(x1 - x0 + 1) * (tempSP[n] - tSP0[n]) + tSP0[n]
402                                         dc.SetPen(tempSPPen)
403                                         dc.DrawPoint(x, h - (tSP * h / 300))
404                                         dc.SetPen(tempPen)
405                                         dc.DrawPoint(x, h - (t * h / 300))
406                                 bt = float(x - x0) / float(x1 - x0 + 1) * (bedTemp - bt0) + bt0
407                                 btSP = float(x - x0) / float(x1 - x0 + 1) * (bedTempSP - btSP0) + btSP0
408                                 dc.SetPen(bedTempSPPen)
409                                 dc.DrawPoint(x, h - (btSP * h / 300))
410                                 dc.SetPen(bedTempPen)
411                                 dc.DrawPoint(x, h - (bt * h / 300))
412                         t0 = temp
413                         bt0 = bedTemp
414                         tSP0 = tempSP
415                         btSP0 = bedTempSP
416                         x0 = x1 + 1
417
418                 del dc
419                 self.Refresh(eraseBackground=False)
420                 self.Update()
421
422                 if len(self._points) > 0 and (time.time() - self._points[0][4]) > w + 20:
423                         self._points.pop(0)
424
425         def addPoint(self, temp, tempSP, bedTemp, bedTempSP):
426                 if len(self._points) > 0 and time.time() - self._points[-1][4] < 0.5:
427                         return
428                 for n in xrange(0, len(temp)):
429                         if temp[n] is None:
430                                 temp[n] = 0
431                 for n in xrange(0, len(tempSP)):
432                         if tempSP[n] is None:
433                                 tempSP[n] = 0
434                 if bedTemp is None:
435                         bedTemp = 0
436                 if bedTempSP is None:
437                         bedTempSP = 0
438                 self._points.append((temp[:], tempSP[:], bedTemp, bedTempSP, time.time()))
439                 wx.CallAfter(self.UpdateDrawing)
440
441
442 class LogWindow(wx.Frame):
443         def __init__(self, logText):
444                 super(LogWindow, self).__init__(None, title="Error log")
445                 self.textBox = wx.TextCtrl(self, -1, logText, style=wx.TE_MULTILINE | wx.TE_DONTWRAP | wx.TE_READONLY)
446                 self.SetSize((500, 400))
447                 self.Centre()
448                 self.Show(True)