コード例 #1
0
class GUI_MoveRelativeTool:
    def __init__(self, master, distance):
        self.master = master
        self.master.title('Tools')
        self.createWidgets()
        self.set(distance)

    def callback(self, cb):
        self._callback = cb

    def do_callback(self, context, *args):
        if hasattr(self, '_callback'):
            self._callback(context, *args)

    def createWidgets(self):

        self.mainmenu = Menu(self.master)
        self.mainmenu.config(borderwidth=1)
        self.master.config(menu=self.mainmenu)

        self.filemenu = Menu(self.mainmenu)
        self.filemenu.config(tearoff=0)
        self.mainmenu.add_cascade(label='File',
                                  menu=self.filemenu,
                                  underline=0)
        self.filemenu.add_command(label='Apply', command=self.wApplyCB)
        self.filemenu.add_command(label='Cancel', command=self.wCancelCB)

        self.master.grid_rowconfigure(0, weight=1)
        self.master.grid_columnconfigure(0, weight=1)

        w = wFrame = LabelFrame(self.master, text='Move relative')

        w.grid(row=0, column=0, sticky=NSEW, padx=5, pady=5)
        w.grid_columnconfigure(0, weight=0)
        w.grid_columnconfigure(1, weight=1)

        w = Label(wFrame, text='Distance (mm) :', anchor=E)
        w.grid(row=0, column=0, sticky=NSEW)

        w = self.wDistance = XFloatEntry(wFrame,
                                         bg='white',
                                         width=10,
                                         borderwidth=2,
                                         justify=LEFT)
        w.grid(row=0, column=1, sticky=NSEW)
        w.callback(self.wEnterCB)
        w.enable_color(enable=False)

    def wApplyCB(self):
        self.do_callback(APPLY, self.wDistance.get() * mm_to_m)

    def wEnterCB(self, *args):
        self.do_callback(ENTER, self.wDistance.get() * mm_to_m)

    def wCancelCB(self):
        self.do_callback(CANCEL)

    def set(self, distance):
        self.wDistance.set(round(distance * m_to_mm, 1))
コード例 #2
0
 def _add_menu(self, name):
     """Añade un menú a la barra de menus"""
     menu_aux = Menu(self._menu_bar)
     menu_aux.config(title=name)
     # FIXME: arreglar la inclusión de posicionamiento del menú
     # si queremos cambiar para que se pueda añadir un menu en la posicón
     # que queremos basta con poner un indice en los parametros de la
     # función y cambiar el indice por el len de la siguiente linea
     self._menus.insert(len(self._menus), menu_aux)
コード例 #3
0
ファイル: gas.py プロジェクト: urrfinjuss/gas-network
	def initUI(self):
		self.parent.title("Gas Model")
		self.fonts = {'fontname'   : 'Helvetica',
		    'color'      : 'r',
		    'fontweight' : 'bold',
		    'fontsize'   : 14}
		self.npts = 32;
		self.sounds = 377.9683;
		self.skip = 1000.
		self.dt = 5000.*self.skip/(self.npts * self.sounds)

		menubar = Menu(self.parent)
		menubar.config(font=("Helvetica", 14, "italic"))
		self.parent.config(menu=menubar)

		fileMenu = Menu(menubar, tearoff=0)
		fileMenu.config(font=("Helvetica", 14, "italic"))
		fileMenu.add_command(label="Load", command=self.onLoad)
		fileMenu.add_command(label="Close", command=self.onClose)
		fileMenu.add_command(label="Exit", command=self.quit)
		menubar.add_cascade(label="File", menu=fileMenu)
		
		fileMenu2 = Menu(menubar, tearoff=0)
		fileMenu2.config(font=("Helvetica", 14, "italic"))
		fileMenu2.add_command(label="Set Parameters", command=self.quit)
		menubar.add_cascade(label="Parameters", menu=fileMenu2)

		lbl1 = Label(self.parent, 
			text="Gas Network", 
			fg = "black", 
			font=("Helvetica", 14, "bold"))
	        lbl1.grid(sticky="N", pady=4, padx=5, row=0, column=0, columnspan=2)

		self.f = plt.figure(figsize=(5,4), dpi=80)
		self.cmap = plt.cm.jet #ok
		self.a = self.f.add_subplot(111)
		self.a.axis([-1, 1, -1, 1])
		self.a.axis('off')

		self.canvas = FigureCanvasTkAgg(self.f, master=self.parent)
		self.G = nx.Graph()
		nx.draw_networkx(self.G, pos=nx.spring_layout(self.G), ax=self.a)
		self.canvas.show()
		self.canvas.get_tk_widget().config(width=800-20, height=600-100)
		self.canvas.get_tk_widget().grid(sticky="NW", pady=4, padx=5, row=1, column=0, columnspan=6, rowspan=6) 
		self.txt = Text(self.parent, width=54, height=33);
		self.txt.grid(sticky="NW", pady=4, padx=5, row=1, column=8, columnspan=4, rowspan=6)	

		self.log = Text(self.parent, width=112, height=6);
		self.log.grid(sticky="NW", pady=4, padx=5, row=7, column=0, columnspan=6,rowspan=2)

		RunButton = Button(self.parent, text="Run", width=10, command=self.onRun).grid(sticky='SW', pady=4, padx=5, row=7, column=8)
		DrawButton = Button(self.parent, text="Draw", width=10, command=self.onDraw).grid(sticky='SW', pady=4, padx=5, row=7, column=9)
		StopButton = Button(self.parent, text="Stop", width=10, command=self.onStop).grid(sticky='SW', pady=4, padx=5, row=8, column=9)
		QuitButton = Button(self.parent, text="Quit", width=10, command=self.quit ).grid(sticky='SW', pady=4, padx=5, row=7, column=10)
		self.Loaded = False
		self.Animate = False
コード例 #4
0
ファイル: tk_appwindow.py プロジェクト: plewto/Llia
 def menu(master):
     m = Menu(master, tearoff=0)
     m.config(background=factory.bg(), foreground=factory.fg())
     return m
コード例 #5
0
class GUI:

    runModeMenuItems = {
        RUN_MODE_MONITOR: 'Monitor',
    }

    def __init__(self, master, sample):
        self.master = master
        self.sample = sample
        self.master.title('Sample positioner')

        self.createWidgets(self.master)
        self.blank_parameters()
        self.putBanner()

    def callback(self, cb):
        self._callback = cb

    def do_callback(self, context, *args):
        if hasattr(self, '_callback'):
            self._callback(context, *args)

    def close(self):
        for (w, r, c) in (self.wMCStatusDisplay, ):
            w.close()

    def createWidgets(self, master):

        master.grid_columnconfigure(0, weight=0, minsize=200)
        master.grid_columnconfigure(1, weight=1, minsize=700)
        master.grid_rowconfigure(0, weight=1, minsize=575)
        master.grid_rowconfigure(1, weight=0, minsize=25)

        self.populateMenu(master)

        row = 0
        col = 0
        w = XScroll(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populateDisplayPanel(w.interior)

        col += 1
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populatePlotPanel(w)

        row += 1
        col = 0
        w = Frame(master)
        w.grid(row=row, column=col, columnspan=2, sticky=NSEW)
        self.populateStatusFrame(w)

    def populateMenu(self, master):

        ### Main Menu
        self.mainmenu = Menu(master)
        self.mainmenu.config(borderwidth=1)
        master.config(menu=self.mainmenu)

        self.filemenu = Menu(self.mainmenu)
        self.filemenu.config(tearoff=0)
        self.mainmenu.add_cascade(label='File',
                                  menu=self.filemenu,
                                  underline=0)

        #self.settingsmenu = Menu (self.mainmenu)
        #self.settingsmenu.config (tearoff = 0)
        #self.mainmenu.add_cascade (
        #label = 'Settings', menu = self.settingsmenu, underline = 0)

        self.toolsmenu = Menu(self.mainmenu)
        self.toolsmenu.config(tearoff=0)
        self.mainmenu.add_cascade(label='Tools',
                                  menu=self.toolsmenu,
                                  underline=0)

        # ++++ Populating file menu ++++

        menu_items = [ \
         ('Connect'     , self.wConnectDeviceCB),
         ('Hide'        ,       self.wHideCB) \
        ]

        for (l, c) in menu_items:
            self.filemenu.add_command(label=l, command=c)

        # ++++ Populating settings menu ++++

        #menu_items = [ \
        #('Pitch'     , self.wPitchSettingCB) \
        #]

        #for (l, c) in menu_items:
        #self.settingsmenu.add_command (label = l, command = c)

        # ++++ Populating tools menu ++++

        menu_items = [ \
         ('Reset'                 , self.wResetDeviceCB ),
         ('Move absolute'         , self.wMoveAbsoluteCB),
         ('Move relative'         , self.wMoveRelativeCB),
         ('Stop'                  , self.wStopDeviceCB  )  \
        ]

        for (l, c) in menu_items:
            self.toolsmenu.add_command(label=l, command=c)

    def populateDisplayPanel(self, master):

        master.grid_columnconfigure(0, weight=1, minsize=230)

        row = 0
        col = 0
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.wMCStatusDisplay = (GUI_MCStatusDisplay(w), row, col)

        row += 1
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populateControlFrame(w)

    def populateControlFrame(self, master):

        master.grid_columnconfigure(0, weight=1)

        row = 0
        col = 0
        w = LabelFrame(master, text='Control')
        w.grid(row=row, column=col, sticky=NSEW, padx=5, pady=5)
        self.populateControlFrameWidgets(w)

    def populateControlFrameWidgets(self, master):

        master.grid_columnconfigure(0, weight=1)
        master.grid_columnconfigure(1, weight=1)

        row = 0
        col = 0
        w = Label(master, text="Control mode: ")
        w.grid(row=row, column=col, sticky=NSEW)

        col += 1
        var = self.runMode = StringVar()
        options = self.runModeMenuItems.values()
        w = self.wRunMode = OptionMenu(master,
                                       var,
                                       *options,
                                       command=self.wRunModeCB)
        w.config(anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)

        row += 1
        col = 0
        w = self.wStart = Button(master, text='Start', command=self.wStartCB)
        w.grid(row=row, column=col, sticky=NSEW)

        col += 1
        w = self.wFinish = Button(master,
                                  text='Finish',
                                  state=DISABLED,
                                  command=self.wFinishCB)
        w.grid(row=row, column=col, sticky=NSEW)

    # ++++++++++++++++++++++++++++++++++++++++++++++++++

    def populatePlotPanel(self, master):

        master.grid_rowconfigure(0, weight=1)
        master.grid_columnconfigure(0, weight=1)

        w = self.wPlots = XTab(master)
        w.grid(row=0, column=0, sticky=NSEW)

    def newPlot(self, name):
        return Plot2D.Plot2D(self.wPlots.add(name))

    def clearPlot(self):
        self.wPlots.clear()
        self.putBanner()

    # ++++++++++++++++++++++++++++++++++++++++++++++++++

    def populateStatusFrame(self, master):

        master.grid_columnconfigure(0, weight=1)
        #master.grid_rowconfigure    (0, weight = 1)

        row = 0
        col = 0
        w = self.wStatus = Label(master, text='...', anchor=W, width=10)
        w.grid(row=row, column=col, sticky=NSEW)

    def set_status(self, text):

        lt = localtime(systime())
        time_stamp = (str('%02d' % lt.tm_hour) + ':' +
                      str('%02d' % lt.tm_min) + ':' + str('%02d' % lt.tm_sec))

        text = '<' + time_stamp + ':XMC> ' + text
        print text

        old_text = self.wStatus['text']
        new_text = text + '    .    ' + old_text
        new_text = new_text[:1024]
        self.wStatus['text'] = new_text

    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def setConnectionStatus(self, status):

        if status == DEVICE_CONNECTING:
            self.filemenu.entryconfig(0,
                                      label='Connecting',
                                      state=DISABLED,
                                      command=None)

        elif status == DEVICE_CONNECTED:
            self.filemenu.entryconfig(0,
                                      label='Disconnect',
                                      state=NORMAL,
                                      command=self.wDisconnctDeviceCB)

            self.set_status('Sample positioner connected')

        elif status == DEVICE_DISCONNECTING:
            self.filemenu.entryconfig(0,
                                      label='Disconnecting',
                                      state=DISABLED,
                                      command=None)

        elif status == DEVICE_DISCONNECTED:

            self.filemenu.entryconfig(0,
                                      label='Connect',
                                      state=NORMAL,
                                      command=self.wConnectDeviceCB)

            self.wMCStatusDisplay[0].blank_parameters()
            self.set_status('Sample positioner disconnected')

        elif status == DEVICE_NOT_FOUND:
            self.filemenu.entryconfig(0,
                                      label='Connect',
                                      state=NORMAL,
                                      command=self.wConnectDeviceCB)

            self.wMCStatusDisplay[0].blank_parameters()
            self.set_status('Sample positioner not found')

        else:
            raise ValueError(status)

    def wHideCB(self):
        self.master.withdraw()

    def wConnectDeviceCB(self):
        self.do_callback(CONNECT_DEVICE)

    def wDisconnctDeviceCB(self):
        self.do_callback(DISCONNECT_DEVICE)

    # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    def wStartCB(self):
        self.do_callback(START_RUN, self.getRunMode())

    def wFinishCB(self):
        self.do_callback(FINISH_RUN)

    def setRunControlStatus(self, status):

        if status == RUN_STARTING:
            self.wRunMode.config(state=DISABLED)
            self.wStart.config(text='Starting', state=DISABLED)
            self.wFinish.config(text='Finish', state=DISABLED)

        elif status == RUN_STARTED:
            self.wRunMode.config(state=DISABLED)
            self.wStart.config(text='Started', state=DISABLED)
            self.wFinish.config(text='Finish', state=NORMAL)

        elif status == RUN_FINISHING:
            self.wRunMode.config(state=DISABLED)
            self.wStart.config(text='Started', state=DISABLED)
            self.wFinish.config(text='Finishing', state=DISABLED)

        elif status == RUN_FINISHED:
            self.wRunMode.config(state=NORMAL)
            self.wStart.config(text='Start', state=NORMAL)
            self.wFinish.config(text='Finish', state=DISABLED)

    def wRunModeCB(self, *args):
        self.do_callback(RUN_MODE, self.getRunMode())

    def getRunMode(self):
        runModes = {v: k for (k, v) in self.runModeMenuItems.items()}
        return runModes.get(self.runMode.get())

    def setRunMode(self, mode):

        self.runMode.set(self.runModeMenuItems.get(mode))

        if mode == RUN_MODE_MONITOR: pass
        else: raise ValueError(mode)

    def wPitchSettingCB(self):
        self.do_callback(OPEN_DIALOG, PITCH_SETTING_DIALOG)

    def wResetDeviceCB(self):
        self.do_callback(RESET_DEVICE)

    def wMoveAbsoluteCB(self):
        self.do_callback(OPEN_DIALOG, MOVE_ABSOLUTE_DIALOG)

    def wMoveRelativeCB(self):
        self.do_callback(OPEN_DIALOG, MOVE_RELATIVE_DIALOG)

    def wStopDeviceCB(self):
        self.do_callback(STOP_DEVICE)

    def setMCStatusDisplay(self, state, position, remainingDistance):
        (w, row, col) = self.wMCStatusDisplay
        w.setValues(state, position, remainingDistance)

    def setMCProgressBarDisplay(self, position):
        (w, row, col) = self.wMCStatusDisplay
        w.setBar(position)

    def setStatusJammed(self):
        (w, row, col) = self.wMCStatusDisplay
        w.setStatusJammed()

    def setMCProgressBarMin(self, position):
        (w, row, col) = self.wMCStatusDisplay
        w.setBarMin(position)

    def setMCProgressBarMax(self, position):
        (w, row, col) = self.wMCStatusDisplay
        w.setBarMax(position)

    def blank_parameters(self):
        self.wMCStatusDisplay[0].blank_parameters()

    def putBanner(self):
        w = GUI_Banner(self.wPlots.add('Welcome'))
        w.grid(row=0, column=0, sticky=NSEW)
コード例 #6
0
ファイル: app_sample.py プロジェクト: vishnu2709/Qrius
class GUI:
    def __init__(self, master):
        self.master = master
        self.master.title('Sample details')
        self.createWidgets()

    def callback(self, cb):
        self._callback = cb

    def do_callback(self, context, *args):
        if hasattr(self, '_callback'):
            self._callback(context, *args)

    def createWidgets(self):

        ### Main Menu
        self.mainmenu = Menu(self.master)
        self.mainmenu.config(borderwidth=1)
        self.master.config(menu=self.mainmenu)

        self.filemenu = Menu(self.mainmenu)
        self.filemenu.config(tearoff=0)
        self.mainmenu.add_cascade(label='File',
                                  menu=self.filemenu,
                                  underline=0)
        self.filemenu.add_command(label='New', command=self.wNewCB)
        self.filemenu.add_command(label='Apply', command=self.wApplyCB)
        self.filemenu.add_command(label='Cancel', command=self.wCancelCB)

        self.master.grid_rowconfigure(0, weight=1)
        self.master.grid_columnconfigure(0, weight=1)

        # ++++ Temperature settings ++++
        w = wFrame = LabelFrame(self.master, text='Sample details')

        w.grid(row=0, column=0, sticky=NSEW, padx=5, pady=5)
        w.grid_columnconfigure(0, weight=0)
        w.grid_columnconfigure(1, weight=1)

        # ++++ Sample name ++++
        row = 0
        col = 0
        w = Label(wFrame, text='Name:', anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)

        row += 1
        col = 0
        self.sampleName = StringVar()
        w = self.wName = Entry(wFrame,
                               bg='white',
                               width=10,
                               borderwidth=2,
                               justify=LEFT,
                               textvariable=self.sampleName)
        w.grid(row=row, column=col, sticky=NSEW)

        # ++++ Sample ID ++++
        row += 1
        col = 0
        w = Label(wFrame, text='ID:', anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)

        row += 1
        col = 0
        self.sampleID = StringVar()
        w = self.wIdent = Entry(wFrame,
                                bg='white',
                                width=10,
                                borderwidth=2,
                                justify=LEFT,
                                textvariable=self.sampleID)
        w.grid(row=row, column=col, sticky=NSEW)

        # ++++ Sample description ++++
        row += 1
        col = 0
        w = Label(wFrame, text='Description:', anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)

        row += 1
        col = 0
        w = self.wDescription = Text(wFrame)
        w.grid(row=row, column=col, sticky=NSEW)

    def wNewCB(self):
        self.do_callback(NEW)

    def wApplyCB(self):
        self.do_callback(APPLY, self.sampleName.get(), self.sampleID.get(),
                         self.wDescription.get(1.0, END))

    def wCancelCB(self):
        self.do_callback(CANCEL)

    def set(self, *args):
        (name, ident, desc) = args
        self.sampleName.set(name)
        self.sampleID.set(ident)
        self.wDescription.delete(1.0, END)
        self.wDescription.insert(1.0, desc)
コード例 #7
0
ファイル: tk_appwindow.py プロジェクト: kaos/Llia
 def menu(master):
     m = Menu(master, tearoff=0)
     m.config(background=factory.bg(), foreground=factory.fg())
     return m
コード例 #8
0
ファイル: AppAnalyzer.py プロジェクト: vishnu2709/Qrius
class AppAnalyzer(Frame):
    def __init__(self, master):
        Frame.__init__(self, master)

        self.run = None
        self.filename = None

        master.title('Qrius: Analyzer')
        master.protocol('WM_DELETE_WINDOW', self.wQuitCB)
        self.populateMenu(master)

        master.grid_columnconfigure(0, weight=1)
        master.grid_rowconfigure(0, weight=1)
        self.createWidgets(self)

    def createWidgets(self, master):

        master.grid_columnconfigure(0, weight=0, minsize=250)
        master.grid_columnconfigure(1, weight=1, minsize=650)
        master.grid_rowconfigure(0, weight=1)
        master.grid_rowconfigure(1, weight=0)

        row = 0
        col = 0
        w = XScroll(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populateAxisPanel(w.interior)

        col += 1
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW)
        self.populatePlotPanel(w)

        row += 1
        col = 0
        w = Frame(master)
        w.grid(row=row, column=col, columnspan=2, sticky=NSEW)
        self.populateStatusPanel(w)

    def populateMenu(self, master):

        ### Main Menu
        self.mainmenu = Menu(master)
        self.mainmenu.config(borderwidth=1)
        master.config(menu=self.mainmenu)

        # ++++++++++++++++++++++++++++++++++++++++++++++++++

        self.filemenu = Menu(self.mainmenu)
        self.filemenu.config(tearoff=0)
        self.mainmenu.add_cascade(label='File',
                                  menu=self.filemenu,
                                  underline=0)

        self.filemenu.add_command(label='Open', command=self.wOpenFileCB)
        self.filemenu.add_command(label='Export', command=self.wExportCB)
        self.filemenu.add_separator()
        self.filemenu.add_command(label='Exit', command=self.wQuitCB)

    def populateAxisPanel(self, master):

        master.grid_columnconfigure(0, weight=1)

        row = 0
        col = 0
        w = LabelFrame(master, text='Axes')
        w.grid(row=row, column=col, sticky=NSEW, padx=5, pady=5)
        self.populateAxesFrame(w)

        row += 1
        w = LabelFrame(master, text='Available fields')
        w.grid(row=row, column=col, sticky=NSEW, padx=5, pady=5)
        self.populateFieldsFrame(w)

        row += 1
        w = Frame(master)
        w.grid(row=row, column=col, sticky=NSEW, padx=5, pady=5)
        self.populateButtonFrame(w)

        row += 1
        w = LabelFrame(master, text='Sample details')
        w.grid(row=row, column=col, sticky=NSEW, padx=5, pady=5)
        self.populateSampleFrame(w)

    def populateAxesFrame(self, master):

        master.grid_columnconfigure(0, weight=1)

        row = 0
        col = 0
        w = Label(master, text='X axis:', anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)

        row += 1
        var = self.XAxis = StringVar(value='...')
        w = self.wXAxes = OptionMenu(master, var, var.get())
        w.config(anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)
        self.rowXAxes = row
        self.colXAxes = col

        row += 1
        w = Label(master, text='Y axis:', anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)

        row += 1
        var = self.YAxis = StringVar(value='...')
        w = self.wYAxes = OptionMenu(master, var, var.get())
        w.config(anchor=W)
        w.grid(row=row, column=col, sticky=NSEW)
        self.rowYAxes = row
        self.colYAxes = col

    def populateFieldsFrame(self, master):

        master.grid_columnconfigure(0, weight=1)

        row = 0
        col = 0
        w = self.wFields = Label(master, text='...', anchor=W, justify=LEFT)
        w.grid(row=row, column=col, sticky=NSEW)

    def populateButtonFrame(self, master):

        master.grid_columnconfigure(0, weight=1, minsize=100)
        master.grid_columnconfigure(1, weight=1, minsize=100)

        row = 0
        col = 0
        w = Button(master, text='Clear', command=self.wClearPlotCB)
        w.grid(row=row, column=col, sticky=NSEW)

        col += 1
        w = Button(master, text='Add', command=self.wPlotDataCB)
        w.grid(row=row, column=col, sticky=NSEW)

    def populateSampleFrame(self, master):

        master.grid_columnconfigure(0, weight=1, minsize=100)
        master.grid_columnconfigure(1, weight=1, minsize=100)

        # Sample name

        row = 0
        col = 0
        w = Label(master, text='Name', anchor=W, justify=LEFT)
        w.grid(row=row, column=col, sticky=NSEW)

        col += 1
        w = Label(master, text='...', anchor=E, justify=LEFT)
        w.grid(row=row, column=col, sticky=NSEW)
        self.wSampleName = w

        # Sample ID

        row += 1
        col = 0
        w = Label(master, text='ID', anchor=W, justify=LEFT)
        w.grid(row=row, column=col, sticky=NSEW)

        col += 1
        w = Label(master, text='...', anchor=E, justify=LEFT)
        w.grid(row=row, column=col, sticky=NSEW)
        self.wSampleID = w

        # Sample description

        row += 1
        col = 0
        w = Label(master, text='Description', anchor=W, justify=LEFT)
        w.grid(row=row, column=col, columnspan=2, sticky=NSEW)

        row += 1
        col = 0
        w = Text(master, width=20, state=DISABLED)
        w.grid(row=row, column=col, columnspan=2, sticky=NSEW)
        self.wSampleDescription = w

    def populatePlotPanel(self, master):

        master.grid_rowconfigure(0, weight=1)
        master.grid_columnconfigure(0, weight=1)
        w = self.wPlot = Plot2D(master)

    def populateStatusPanel(self, master):

        master.grid_columnconfigure(0, weight=1)
        row = 0
        col = 0
        w = self.wStatus = Label(master, text='...', anchor=W, width=30)
        w.grid(row=row, column=col, sticky=NSEW)

    def wQuitCB(self):
        self.master.destroy()

    def wOpenFileCB(self):

        filetypes = [('XPLORE file', '*.xpl'), ('Old XPLORE file', '*.xp*'),
                     ('All files', '*.*')]

        try:

            folder = (os.path.dirname(self.filename) if self.filename != None
                      else Preferences.getDataFolder())

            fd = askopenfile(parent=self.master,
                             initialdir=folder,
                             filetypes=filetypes)

            if fd != None:

                self.filename = fd.name
                self.run = XDict(fd)
                fd.close()

                self.master.title(self.filename)
                self.populateAxes(self.run.data_keys())

                sample = self.run.sample()
                if type(sample) == tuple: self.populateSample(*sample)
                else: self.populateSample()

                #self.wPlot.clear()
                #self.wPlot.redraw()

        except (OSError, IOError) as e:
            text = 'Open failed: ' + str(e)
            self.set_status(text)

        except XDictError as e:
            text = 'Open failed: ' + str(e) + ' ' + str(e)
            self.set_status(text)

    def wExportCB(self):

        try:

            if self.run == None: return

            # +++++++ Generate table in RAM +++++++

            units = []
            columns = []
            data_keys = self.run.data_keys()

            for key in data_keys:
                (data, unit) = self.run.get_data(key)
                units.append(unit)
                columns.append(data)

            # +++++++ Open export file +++++++

            (filename, extension) = os.path.splitext(self.filename)
            filename = filename + os.extsep + 'csv'
            fd = open(filename, 'w')

            # +++++++ Save sample details +++++++

            sample = self.run.sample()
            if type(sample) == tuple:

                # ++++ Sample name ++++

                try:
                    name = str(sample[0])
                except IndexError, TypeError:
                    name = '...'
                fd.write('#Sample name: ' + name + '\n')

                # ++++ Sample ID ++++

                try:
                    ident = str(sample[1])
                except IndexError, TypeError:
                    ident = '...'
                fd.write('#Sample ID: ' + ident + '\n')

                # ++++ Sample description ++++

                try:
                    desc = str(sample[2])
                except IndexError, TypeError:
                    desc = '...'
                label = '#Sample description: '
                desc = desc.replace('\n', '\n' + label)
                fd.write(label + desc + '\n')