mySQL을 설치해서 파이썬과 같이 사용해 보는 GUI프로그래밍 입니다.

in #kr6 years ago

지난주와 이번주 보고 있는 책이 파이썬 GUI 프로그래밍 책입니다.

mySQL을 설치해서 파이썬과 같이 사용해 보는 GUI프로그래밍 입니다.
파이썬이 다방면에서 좋은 결과물들을 많이 만들어 내고 있습니다. IT개발 분야에서 프론트 엔드, 백엔드, 웹 분야, AI와 데이터 사이언스를 가리지 않고 힘을 내고 있습니다.

저는 주로 개발하고 강의하던 분야가 닷넷과 아이폰이였는데 4년전부터 파이썬 분야로 넘어와서 강의를 하고 있습니다. ^^

혹시 mySQL이 처음이시면 아래의 주소에서 커뮤니티 에디션을 받으시면 됩니다. 최신 버전은 8.0이고 이전 버전은 5.7을 받으셔도 됩니다. 저는 5.7 버전을 받았습니다.

아래의 주소에서 윈도우용 인스톨러가 있는 버전을 받으시면 설치가 편하게 진행됩니다.
https://dev.mysql.com/downloads/file/?id=479142

2018-10-15_15-32-37.png

커뮤니티 버전은 대부분 무료로 제공됩니다.

2018-10-15_15-32-16.png

연습용으로 또는 개발용으로 설치할 예정입니다. 대부분 기본 옵션을 선택하시면 됩니다.

2018-10-15_15-33-20.png

2018-10-15_15-35-42.png

2018-10-15_15-36-07.png

2018-10-15_15-36-32.png

2018-10-15_15-37-14.png

2018-10-15_15-39-08.png

암호만 추가로 입력하시면 되고 계정을 추가하시면 됩니다. 저는 "admin"이라는 계정을 추가해서 암호를 지정했습니다.

파이썬 3.6 버전이 미리 설치되어 있습니다. 여기에 mySQL에 접속하려면 약간의 추가 모듈을 pip명령으로 설치하시면 됩니다. 파이썬 커넥터 드라이버를 설치해야 한다.
https://dev.mysql.com/doc/connector-python/en/connector-python-installation-binary.html

커맨드창을 오픈해서 아래와 같이 실행한다.
pip install mysql-connector-python

2018-10-15_15-53-54.png

아래의 샘플 코드는 크게 3개의 파일로 구성되어 있습니다.

  1. 연결문자열을 별도로 관리할 수 있는 파일입니다.
# GuiDBConfig.py
#접속 관련 정보를 딕셔너리에 저장
dbConfig = {
    'user':'jonathan',
    'password':'1234',
    'host':'127.0.0.1',
}

2)SQL구문을 실행하는 데이터를 다루는 클래스 파일입니다.

# GUI_MySQL_class.py
# 아래의 코드를 수정해야 한다. 
import mysql.connector as mysql 
import GuiDBConfig as guiConf 

class MySQL():
    # class variable
    GUIDB  = 'GuiDB'   
     
    #------------------------------------------------------
    def connect(self):
        # connect by unpacking dictionary credentials
        conn = mysql.connect(**guiConf.dbConfig)
    
        # create cursor 
        cursor = conn.cursor()    
            
        return conn, cursor
    
    #------------------------------------------------------    
    def close(self, cursor, conn):        
        # close cursor
        cursor.close()
                
        # close connection to MySQL
        conn.close()    

    #------------------------------------------------------        
    def showDBs(self):
        # connect to MySQL
        conn, cursor = self.connect()        
        
        # print results
        cursor.execute("SHOW DATABASES")
        print(cursor)
        print(cursor.fetchall())

        # close cursor and connection
        self.close(cursor, conn)
                   
    #------------------------------------------------------
    def createGuiDB(self):
        # connect to MySQL
        conn, cursor = self.connect()
        
        try:
            cursor.execute(
                "CREATE DATABASE {} DEFAULT CHARACTER SET 'utf8'".format(MySQL.GUIDB))
        except mysql.Error as err:
            print("Failed to create DB: {}".format(err))        

        # close cursor and connection
        self.close(cursor, conn) 

    #------------------------------------------------------
    def dropGuiDB(self):
        # connect to MySQL
        conn, cursor = self.connect()
        try:
            cursor.execute(
                "DROP DATABASE {}".format(MySQL.GUIDB))
        except mysql.Error as err:
            print("Failed to drop DB: {}".format(err))        

        # close cursor and connection
        self.close(cursor, conn) 
             
    #------------------------------------------------------        
    def useGuiDB(self, cursor):
        '''Expects open connection.'''
        # select DB
        cursor.execute("USE guidb")
                      
    #------------------------------------------------------
    def createTables(self):
        # connect to MySQL
        conn, cursor = self.connect()
    
        self.useGuiDB(cursor)
        
        # create Table inside DB
        cursor.execute("CREATE TABLE Books (       \
              Book_ID INT NOT NULL AUTO_INCREMENT, \
              Book_Title VARCHAR(25) NOT NULL,     \
              Book_Page INT NOT NULL,              \
              PRIMARY KEY (Book_ID)                \
            ) ENGINE=InnoDB")
        
        # create second Table inside DB
        cursor.execute("CREATE TABLE Quotations ( \
                Quote_ID INT AUTO_INCREMENT,      \
                Quotation VARCHAR(250),           \
                Books_Book_ID INT,                \
                PRIMARY KEY (Quote_ID),           \
                FOREIGN KEY (Books_Book_ID)       \
                    REFERENCES Books(Book_ID)     \
                    ON DELETE CASCADE             \
            ) ENGINE=InnoDB")   
            
        # close cursor and connection
        self.close(cursor, conn) 
        
    #------------------------------------------------------
    def createTablesNoFK(self):
        # connect to MySQL
        conn, cursor = self.connect()
    
        self.useGuiDB(cursor)
        
        # create Table inside DB
        cursor.execute("CREATE TABLE Books (       \
              Book_ID INT NOT NULL AUTO_INCREMENT, \
              Book_Title VARCHAR(25) NOT NULL,     \
              Book_Page INT NOT NULL,              \
              PRIMARY KEY (Book_ID)                \
            ) ENGINE=InnoDB")
                
        # create second Table inside DB -- 
        # No FOREIGN KEY relation to Books Table
        cursor.execute("CREATE TABLE Quotations ( \
                Quote_ID INT AUTO_INCREMENT,      \
                Quotation VARCHAR(250),           \
                Books_Book_ID INT,                \
                PRIMARY KEY (Quote_ID)            \
            ) ENGINE=InnoDB")   
            
        # close cursor and connection
        self.close(cursor, conn) 
          
    #------------------------------------------------------
    def dropTables(self):
        # connect to MySQL
        conn, cursor = self.connect()
    
        self.useGuiDB(cursor)
        
        cursor.execute("DROP TABLE quotations")
        cursor.execute("DROP TABLE books")   
    
        # close cursor and connection
        self.close(cursor, conn)    

    #------------------------------------------------------
    def showTables(self):
        # connect to MySQL
        conn, cursor = self.connect()
    
        # show Tables from guidb DB
        cursor.execute("SHOW TABLES FROM guidb") 
        print(cursor.fetchall())
        
        # close cursor and connection
        self.close(cursor, conn)          
            
    #------------------------------------------------------        
    def insertBooks(self, title, page, bookQuote):
        # connect to MySQL
        conn, cursor = self.connect()
        
        self.useGuiDB(cursor)
        
        # insert data
        cursor.execute("INSERT INTO books (Book_Title, Book_Page) VALUES (%s,%s)", (title, page))

        # last inserted auto increment value   
        keyID = cursor.lastrowid 
        # print(keyID)
                
        cursor.execute("INSERT INTO quotations (Quotation, Books_Book_ID) VALUES (%s, %s)", \
                       (bookQuote, keyID))
                
        # commit transaction
        conn.commit ()

        # close cursor and connection
        self.close(cursor, conn)

    #------------------------------------------------------        
    def insertBooksExample(self):
        # connect to MySQL
        conn, cursor = self.connect()
        
        self.useGuiDB(cursor)
        
        # insert hard-coded data
        cursor.execute("INSERT INTO books (Book_Title, Book_Page) VALUES ('Design Patterns', 17)")
        
        # last inserted auto increment value   
        keyID = cursor.lastrowid 
        print(keyID)
                
        cursor.execute("INSERT INTO quotations (Quotation, Books_Book_ID) VALUES (%s, %s)", \
                       ('Programming to an Interface, not an Implementation', keyID))
        
        # commit transaction
        conn.commit ()
    
        # close cursor and connection
        self.close(cursor, conn)
        
    #------------------------------------------------------        
    def showBooks(self):
        # connect to MySQL
        conn, cursor = self.connect()    
        
        self.useGuiDB(cursor)    
        
        # print results
        cursor.execute("SELECT * FROM Books")
        allBooks = cursor.fetchall()
        print(allBooks)

        # close cursor and connection
        self.close(cursor, conn)   
        
        return allBooks     

    #------------------------------------------------------        
    def showColumns(self):
        # connect to MySQL
        conn, cursor = self.connect()   
        
        self.useGuiDB(cursor)      
         
        # execute command
        cursor.execute("SHOW COLUMNS FROM quotations")
        print(cursor.fetchall())
        
        print('\n Pretty Print:\n--------------') 
        from pprint import pprint
        # execute command
        cursor.execute("SHOW COLUMNS FROM quotations")
        pprint(cursor.fetchall())

        # close cursor and connection
        self.close(cursor, conn) 
        
    #------------------------------------------------------        
    def showData(self):
        # connect to MySQL
        conn, cursor = self.connect()   
        
        self.useGuiDB(cursor)      
         
        # execute command
        cursor.execute("SELECT * FROM books")
        print(cursor.fetchall())

        cursor.execute("SELECT * FROM quotations")
        print(cursor.fetchall())
        
        # close cursor and connection
        self.close(cursor, conn) 
        
    #------------------------------------------------------        
    def showDataWithReturn(self):
        # connect to MySQL
        conn, cursor = self.connect()   
        
        self.useGuiDB(cursor)      
         
        # execute command
        cursor.execute("SELECT * FROM books")
        booksData = cursor.fetchall()

        cursor.execute("SELECT * FROM quotations")
        quoteData = cursor.fetchall()
        
        # close cursor and connection
        self.close(cursor, conn) 
        
        # print(booksData, quoteData)
        for record in quoteData:
            print(record)
        
        return booksData, quoteData

    #------------------------------------------------------        
    def updateGOF(self):
        # connect to MySQL
        conn, cursor = self.connect()   
        
        self.useGuiDB(cursor)      
         
        # execute command
        cursor.execute("SELECT Book_ID FROM books WHERE Book_Title = 'Design Patterns'")
        primKey = cursor.fetchall()[0][0]
        print("Primary key=" + str(primKey))

        cursor.execute("SELECT * FROM quotations WHERE Books_Book_ID = (%s)", (primKey,))
        print(cursor.fetchall())
        
        # close cursor and connection
        self.close(cursor, conn) 
        
    #------------------------------------------------------        
    def updateGOF_commit(self):
        # connect to MySQL
        conn, cursor = self.connect()   
        
        self.useGuiDB(cursor)      
         
        # execute command
        cursor.execute("SELECT Book_ID FROM books WHERE Book_Title = 'Design Patterns'")
        primKey = cursor.fetchall()[0][0]
        # print(primKey)

        cursor.execute("SELECT * FROM quotations WHERE Books_Book_ID = (%s)", (primKey,))
        # print(cursor.fetchall())
        
        cursor.execute("UPDATE quotations SET Quotation = (%s) WHERE Books_Book_ID = (%s)", \
                       ("Pythonic Duck Typing: If it walks like a duck and talks like a duck it probably is a duck...", primKey))

        # commit transaction
        conn.commit ()
                
        cursor.execute("SELECT * FROM quotations WHERE Books_Book_ID = (%s)", (primKey,))
        # print(cursor.fetchall())
        
        # close cursor and connection
        self.close(cursor, conn) 
 
 
    #------------------------------------------------------        
    def deleteRecord(self):
        # connect to MySQL
        conn, cursor = self.connect()   
        
        self.useGuiDB(cursor)      
        
        try: 
            # execute command
            cursor.execute("SELECT Book_ID FROM books WHERE Book_Title = 'Design Patterns'")
            primKey = cursor.fetchall()[0][0]
            # print(primKey)
            
            cursor.execute("DELETE FROM books WHERE Book_ID = (%s)", (primKey,))
    
            # commit transaction
            conn.commit ()
        except:
            pass
               
        # close cursor and connection
        self.close(cursor, conn)     
        
                                           
#==========================================================
if __name__ == '__main__': 
    # Create class instance
    mySQL = MySQL()

    #------------------------
#   mySQL.showTables()
#   mySQL.dropTables()
#   mySQL.createTables()
#   mySQL.insertBooks() 
#   mySQL.showTables()
    
    #------------------------
#     mySQL.showDBs()
#     mySQL.createGuiDB()
#     mySQL.showDBs()
     
    #------------------------
#     mySQL.dropGuiDB()
#     mySQL.showDBs()
    
    #------------------------
#     mySQL.createGuiDB()
#     mySQL.dropTables()
#     mySQL.createTables()
#     mySQL.showTables()
     
    #------------------------
#     mySQL.showBooks()
    
    #------------------------
#     mySQL.showColumns()
    
    #------------------------
#     mySQL.insertBooksExample()
    
    #------------------------
#     mySQL.insertBooks('Design Patterns', 7, 'Programming to an Interface, not an Implementation')
#     mySQL.insertBooks('xUnit Test Patterns', 31, 'Philosophy of Test Automation')
#     mySQL.showData()
      
    #------------------------
#     mySQL.showData()
    
    #------------------------
#     mySQL.updateGOF()
    
    #------------------------
#     mySQL.updateGOF_commit()
    
    #------------------------
#     book, quote = mySQL.showData()  
#     book, quote = mySQL.showDataWithReturn()
#     print(book, quote)

    #------------------------
#     mySQL.dropTables()
#     mySQL.createTablesNoFK()
#     mySQL.showTables()
    
#     mySQL.insertBooks('Design Patterns', 7, 'Programming to an Interface, not an Implementation')
#     mySQL.insertBooks('xUnit Test Patterns', 31, 'Philosophy of Test Automation')
#     mySQL.showData()    

    #------------------------
#     mySQL.deleteRecord()
    
    #------------------------
#     mySQL.deleteRecord()    
    mySQL.showData()

3)tkiner모듈 기반으로 만들어져 있는 GUI코드 입니다.

#GUI_MySQL.py
#======================
# imports
#======================
import tkinter as tk
from tkinter import ttk
from tkinter import scrolledtext
from tkinter import Menu
from tkinter import Spinbox
import ToolTip as tt
from threading import Thread
from time import sleep
from queue import Queue
from tkinter import filedialog as fd
from os import path, makedirs
from tkinter import messagebox as mBox
from GUI_MySQL_class import MySQL 

# Module level GLOBALS
GLOBAL_CONST = 42
fDir   = path.dirname(__file__)
netDir = fDir + '\\Backup' 
if not path.exists(netDir):
    makedirs(netDir, exist_ok = True) 
WIDGET_LABEL = ' Widgets Frame '

#=================================================================== 
class OOP():
    def __init__(self): 
        # Create instance
        self.win = tk.Tk()           

        # Add a title       
        self.win.title("Python GUI")   
         
        # Disable resizing the window  
        self.win.resizable(0,0)  
        
        # Create a Queue
        self.guiQueue = Queue() 
                              
        self.createWidgets() 
        
        # populate Tab 2 Entries      
        self.defaultFileEntries()
        
        # create MySQL instance
        self.mySQL = MySQL()
                
    def defaultFileEntries(self): 
        self.fileEntry.delete(0, tk.END)
        self.fileEntry.insert(0, 'Z:\\')        # bogus path
        self.fileEntry.config(state='readonly')         

        self.netwEntry.delete(0, tk.END)
        self.netwEntry.insert(0, 'Z:\\Backup')  # bogus path                      
    
    # Combobox callback 
    def _combo(self, val=0):
        value = self.combo.get()
        self.scr.insert(tk.INSERT, value + '\n')
    
    # Spinbox callback 
    def _spin(self):
        value = self.spin.get()
        self.scr.insert(tk.INSERT, value + '\n')
                
    # Checkbox callback  
    def checkCallback(self, *ignoredArgs):
        # only enable one checkbutton
        if self.chVarUn.get(): self.check3.configure(state='disabled')
        else:             self.check3.configure(state='normal')
        if self.chVarEn.get(): self.check2.configure(state='disabled')
        else:             self.check2.configure(state='normal') 
        
    # Radiobutton callback function
    def radCall(self):
        radSel=self.radVar.get()
        if   radSel == 0: self.mySQL2.configure(text=WIDGET_LABEL + 'in Blue')
        elif radSel == 1: self.mySQL2.configure(text=WIDGET_LABEL + 'in Gold')
        elif radSel == 2: self.mySQL2.configure(text=WIDGET_LABEL + 'in Red')        

    # Exit GUI cleanly
    def _quit(self):
        self.win.quit()
        self.win.destroy()
        exit() 
       
    def methodInAThread(self, numOfLoops=10):
        for idx in range(numOfLoops):
            sleep(1)
            self.scr.insert(tk.INSERT, str(idx) + '\n') 
        sleep(1)
        print('methodInAThread():', self.runT.isAlive())
            
    # Running methods in Threads
    def createThread(self, num):
        self.runT = Thread(target=self.methodInAThread, args=[num])
        self.runT.setDaemon(True)    
        self.runT.start()
        print(self.runT)
        print('createThread():', self.runT.isAlive())

        # textBoxes are the Consumers of Queue data
        writeT = Thread(target=self.useQueues, daemon=True)
        writeT.start()
    
    # Create Queue instance  
    def useQueues(self):
        # Now using a class member Queue        
        while True: 
            qItem = self.guiQueue.get()
            print(qItem)
            self.scr.insert(tk.INSERT, qItem + '\n') 

    # Button callback
    def insertQuote(self):
        title = self.bookTitle.get()
        page = self.pageNumber.get()
        quote = self.quote.get(1.0, tk.END)
        print(title)
        print(quote)
        self.mySQL.insertBooks(title, page, quote)     

    # Button callback
    def getQuote(self):
        allBooks = self.mySQL.showBooks()  
        print(allBooks)
        self.quote.insert(tk.INSERT, allBooks)

    # Button callback
    def modifyQuote(self):
        raise NotImplementedError("This still needs to be implemented for the SQL command.")
          
    #####################################################################################    
    def createWidgets(self):    
        # Tab Control introduced here --------------------------------------
        tabControl = ttk.Notebook(self.win)     # Create Tab Control
        
        tab1 = ttk.Frame(tabControl)            # Create a tab 
        tabControl.add(tab1, text='MySQL')      # Add the tab 
        
        tab2 = ttk.Frame(tabControl)            # Add a second tab
        tabControl.add(tab2, text='Widgets')      # Make second tab visible
        
        tabControl.pack(expand=1, fill="both")  # Pack to make visible
        # ~ Tab Control introduced here -----------------------------------------
        
        # We are creating a container frame to hold all other widgets
        self.mySQL = ttk.LabelFrame(tab1, text=' Python Database ')
        self.mySQL.grid(column=0, row=0, padx=8, pady=4)        
        
        # Creating a Label
        ttk.Label(self.mySQL, text="Book Title:").grid(column=0, row=0, sticky='W')
   
        # Adding a Textbox Entry widget
        book = tk.StringVar()
        self.bookTitle = ttk.Entry(self.mySQL, width=34, textvariable=book)
        self.bookTitle.grid(column=0, row=1, sticky='W')     

        # Adding a Textbox Entry widget
        book1 = tk.StringVar()
        self.bookTitle1 = ttk.Entry(self.mySQL, width=34, textvariable=book1)
        self.bookTitle1.grid(column=0, row=2, sticky='W')  
        
        # Adding a Textbox Entry widget
        book2 = tk.StringVar()
        self.bookTitle2 = ttk.Entry(self.mySQL, width=34, textvariable=book2)
        self.bookTitle2.grid(column=0, row=3, sticky='W')  
        
        # Creating a Label
        ttk.Label(self.mySQL, text="Page:").grid(column=1, row=0, sticky='W')
        
        # Adding a Textbox Entry widget
        page = tk.StringVar()
        self.pageNumber = ttk.Entry(self.mySQL, width=6, textvariable=page)
        self.pageNumber.grid(column=1, row=1, sticky='W')     
 
        # Adding a Textbox Entry widget
        page = tk.StringVar()
        self.pageNumber1 = ttk.Entry(self.mySQL, width=6, textvariable=page)
        self.pageNumber1.grid(column=1, row=2, sticky='W')    
        
        # Adding a Textbox Entry widget
        page = tk.StringVar()
        self.pageNumber2 = ttk.Entry(self.mySQL, width=6, textvariable=page)
        self.pageNumber2.grid(column=1, row=3, sticky='W')           
       
        # 입력 버튼 추가하기 
        self.action = ttk.Button(self.mySQL, text="Insert Quote", command=self.insertQuote)   
        self.action.grid(column=2, row=1)

        # 검색 버튼 추가하기(콜백 메서드로 추가됨)
        self.action1 = ttk.Button(self.mySQL, text="Get Quotes", command=self.getQuote)   
        self.action1.grid(column=2, row=2)
        
        # 수정 버튼 추가하기 
        self.action2 = ttk.Button(self.mySQL, text="Mody Quote", command=self.modifyQuote)   
        self.action2.grid(column=2, row=3)
                
        # Add some space around each widget
        for child in self.mySQL.winfo_children(): 
            child.grid_configure(padx=2, pady=4)
            

        quoteFrame = ttk.LabelFrame(tab1, text=' Book Quotation ')
        quoteFrame.grid(column=0, row=1, padx=8, pady=4)    

        # Using a scrolled Text control    
        quoteW  = 40; quoteH = 6
        self.quote = scrolledtext.ScrolledText(quoteFrame, width=quoteW, height=quoteH, wrap=tk.WORD)
        self.quote.grid(column=0, row=8, sticky='WE', columnspan=3)   

        # Add some space around each widget
        for child in quoteFrame.winfo_children(): 
            child.grid_configure(padx=2, pady=4)
                            
        #======================================================================================================               
        # Tab Control 2 
        #======================================================================================================
        # We are creating a container frame to hold all other widgets -- Tab2
        self.mySQL2 = ttk.LabelFrame(tab2, text=WIDGET_LABEL)
        self.mySQL2.grid(column=0, row=0, padx=8, pady=4)
        
        # Creating three checkbuttons
        self.chVarDis = tk.IntVar()
        self.check1 = tk.Checkbutton(self.mySQL2, text="Disabled", variable=self.chVarDis, state='disabled')
        self.check1.select()
        self.check1.grid(column=0, row=0, sticky=tk.W)               
        
        self.chVarUn = tk.IntVar()
        self.check2 = tk.Checkbutton(self.mySQL2, text="UnChecked", variable=self.chVarUn)
        self.check2.deselect()
        self.check2.grid(column=1, row=0, sticky=tk.W )                  
         
        self.chVarEn = tk.IntVar()
        self.check3 = tk.Checkbutton(self.mySQL2, text="Toggle", variable=self.chVarEn)
        self.check3.deselect()
        self.check3.grid(column=2, row=0, sticky=tk.W)                 
     
        # trace the state of the two checkbuttons
        self.chVarUn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())    
        self.chVarEn.trace('w', lambda unused0, unused1, unused2 : self.checkCallback())   
        
        # Radiobutton list
        colors = ["Blue", "Gold", "Red"]
        
        self.radVar = tk.IntVar()
        
        # Selecting a non-existing index value for radVar
        self.radVar.set(99)    
        
        # Creating all three Radiobutton widgets within one loop
        for col in range(3):
            curRad = 'rad' + str(col)  
            curRad = tk.Radiobutton(self.mySQL2, text=colors[col], variable=self.radVar, value=col, command=self.radCall)
            curRad.grid(column=col, row=6, sticky=tk.W, columnspan=3)
            # And now adding tooltips
            tt.create_ToolTip(curRad, 'This is a Radiobutton control.')
            
        # Create a container to hold labels
        labelsFrame = ttk.LabelFrame(self.mySQL2, text=' Labels within a Frame ')
        labelsFrame.grid(column=0, row=7, pady=6)
         
        # Place labels into the container element - vertically
        ttk.Label(labelsFrame, text="Choose a number:").grid(column=0, row=0)
        ttk.Label(labelsFrame, text="Label 2").grid(column=0, row=1)
        
        # Add some space around each label
        for child in labelsFrame.winfo_children(): 
            child.grid_configure(padx=6, pady=1)
            
        number = tk.StringVar()
        self.combo = ttk.Combobox(self.mySQL2, width=12, textvariable=number)
        self.combo['values'] = (1, 2, 4, 42, 100)
        self.combo.grid(column=1, row=7, sticky=tk.W)
        self.combo.current(0)       
        self.combo.bind('<<ComboboxSelected>>', self._combo) 
             
        # Adding a Spinbox widget using a set of values
        self.spin = Spinbox(self.mySQL2, values=(1, 2, 4, 42, 100), width=5, bd=8, command=self._spin) 
        self.spin.grid(column=2, row=7, sticky='W,', padx=6, pady=1)
        
        # Using a scrolled Text control    
        scrolW  = 40; scrolH = 1
        self.scr = scrolledtext.ScrolledText(self.mySQL2, width=scrolW, height=scrolH, wrap=tk.WORD)
        self.scr.grid(column=0, row=8, sticky='WE', columnspan=3)      
                
        # Create Manage Files Frame ------------------------------------------------
        mngFilesFrame = ttk.LabelFrame(tab2, text=' Manage Files: ')
        mngFilesFrame.grid(column=0, row=1, sticky='WE', padx=10, pady=5)
        
        # Button Callback
        def getFileName():
            print('hello from getFileName')
            fDir  = path.dirname(__file__)
            fName = fd.askopenfilename(parent=self.win, initialdir=fDir)
            print(fName)
            self.fileEntry.config(state='enabled')
            self.fileEntry.delete(0, tk.END)
            self.fileEntry.insert(0, fName)
            
            if len(fName) > self.entryLen:
                self.fileEntry.config(width=len(fName) + 3)
                        
        # Add Widgets to Manage Files Frame
        lb = ttk.Button(mngFilesFrame, text="Browse to File...", command=getFileName)     
        lb.grid(column=0, row=0, sticky=tk.W) 
        
        #-----------------------------------------------------        
        file = tk.StringVar()
        self.entryLen = scrolW - 4
        self.fileEntry = ttk.Entry(mngFilesFrame, width=self.entryLen, textvariable=file)
        self.fileEntry.grid(column=1, row=0, sticky=tk.W)
              
        #-----------------------------------------------------
        logDir = tk.StringVar()
        self.netwEntry = ttk.Entry(mngFilesFrame, width=self.entryLen, textvariable=logDir)
        self.netwEntry.grid(column=1, row=1, sticky=tk.W) 

        
        def copyFile():
            import shutil   
            src = self.fileEntry.get()
            file = src.split('/')[-1]  
            dst = self.netwEntry.get() + '\\'+ file
            try:
                shutil.copy(src, dst)   
                mBox.showinfo('Copy File to Network', 'Succes: File copied.')     
            except FileNotFoundError as err:
                mBox.showerror('Copy File to Network', '*** Failed to copy file! ***\n\n' + str(err))
            except Exception as ex:
                mBox.showerror('Copy File to Network', '*** Failed to copy file! ***\n\n' + str(ex))   
        
        cb = ttk.Button(mngFilesFrame, text="Copy File To :   ", command=copyFile)     
        cb.grid(column=0, row=1, sticky=tk.E) 
                
        # Add some space around each label
        for child in mngFilesFrame.winfo_children(): 
            child.grid_configure(padx=6, pady=6)            
            
        # Creating a Menu Bar ==========================================================
        menuBar = Menu(tab1)
        self.win.config(menu=menuBar)
        
        # Add menu items
        fileMenu = Menu(menuBar, tearoff=0)
        fileMenu.add_command(label="New")
        fileMenu.add_separator()
        fileMenu.add_command(label="Exit", command=self._quit)
        menuBar.add_cascade(label="File", menu=fileMenu)
        
        # Add another Menu to the Menu Bar and an item
        helpMenu = Menu(menuBar, tearoff=0)
        helpMenu.add_command(label="About")
        menuBar.add_cascade(label="Help", menu=helpMenu)
        
        # Change the main windows icon
        self.win.iconbitmap('pyc.ico')
        
        # Using tkinter Variable Classes
        strData = tk.StringVar()
        strData.set('Hello StringVar')
        
        # It is not necessary to create a tk.StringVar() 
        strData = tk.StringVar()
        strData = self.spin.get()
        
        # Place cursor into name Entry
        self.bookTitle.focus()        
      
        # Add a Tooltip to the Spinbox
        tt.create_ToolTip(self.spin, 'This is a Spin control.')         
        
        # Add Tooltips to more widgets
        tt.create_ToolTip(self.bookTitle, 'This is an Entry control.')  
        tt.create_ToolTip(self.action, 'This is a Button control.')                      
        tt.create_ToolTip(self.scr,    'This is a ScrolledText control.')   
          
#======================
# Start GUI
#======================
oop = OOP()
oop.win.mainloop()

세번째 파일을 바로 실행하면 아래와 같은 화면이 출력됩니다.
2018-10-16_10-52-09.png

mySQL그룹에 설치된 워크벤치를 실행해서 암호를 입력하고 연결하시면 입력된 결과를 볼 수 있습니다.

2018-10-16_10-56-55.png

Sort:  

요새 데이타사이언스가 뜨면서 어떤 종류든 SQL 하나 정도는 해야 명함을 내민다던데, 파이쏜과 이렇게 연결이 되는군요..
참, #kr-dev 태그 추천드립니다.

아^^ 태그 잊었네요. 고맙습니다.

곰돌이가 @dj-on-steem님의 소중한 댓글에 $0.018을 보팅해서 $0.005을 살려드리고 가요. 곰돌이가 지금까지 총 967번 $14.310을 보팅해서 $12.621을 구했습니다. @gomdory 곰도뤼~

Hello! Your post has been resteemed and upvoted by @ilovecoding because we love coding! Keep up good work! Consider upvoting this comment to support the @ilovecoding and increase your future rewards! ^_^ Steem On!

Reply !stop to disable the comment. Thanks!

Coin Marketplace

STEEM 0.19
TRX 0.15
JST 0.029
BTC 63643.10
ETH 2582.85
USDT 1.00
SBD 2.75