Search code examples
pythonpyqtpyqt4qtexteditqtabwidget

How can I add tabs from PyQt4 to my text editor?


How can I display tabs for my text editor and to be able to replace the "New" action's function to create a new tab and for the "Open" action's to open the file into a new tab?

Here is my code:

#Imports
import sys, os
from PyQt4 import QtGui, QtCore
from PyQt4.QtGui import QApplication, QColumnView, QFileSystemModel, QSplitter, QTreeView
from PyQt4.QtCore import Qt, QDir


class Window(QtGui.QMainWindow):

    #Window Settings
    def __init__(self):
        super(Window, self).__init__()
        self.showMaximized()
        self.setWindowTitle("Editory")
        self.setWindowIcon(QtGui.QIcon('favicon.png'))

        #Text Window
        self.text = QtGui.QTextEdit(self)
        self.text.setTabStopWidth(12)
        self.setCentralWidget(self.text)

        # Font variables
        fontBox = QtGui.QFontComboBox(self)
        fontBox.currentFontChanged.connect(self.FontFamily)

        fontSize = QtGui.QComboBox(self)
        fontSize.setEditable(True)
        fontSize.setMinimumContentsLength(3)

        fontSize.activated.connect(self.FontSize)

        # Font Sizes
        fontSizes = ['6','7','8','9','10','11','12','13','14',
             '15','16','18','20','22','24','26','28',
             '32','36','40','44','48','54','60','66',
             '72','80','88','96']

        for i in fontSizes:
            fontSize.addItem(i)

        #New Input
        new = QtGui.QAction("&New", self)
        new.setShortcut("Ctrl+N")
        new.triggered.connect(self.New)

        #Open Input
        open = QtGui.QAction("&Open", self)
        open.setShortcut("Ctrl+O")
        open.triggered.connect(self.Open)

        #Save Input
        save = QtGui.QAction("&Save", self)
        save.setShortcut("Ctrl+S")
        save.triggered.connect(self.Save)

        #Print Input
        prints = QtGui.QAction("&Print", self)
        prints.setShortcut("Ctrl+P")
        prints.triggered.connect(self.Print)

        #Quit Input
        quit = QtGui.QAction("&Quit", self)
        quit.setShortcut("Ctrl+Q")
        quit.triggered.connect(self.Quit)

        self.statusBar()

        #Menubar
        menubar = self.menuBar()

        #File Menu
        file = menubar.addMenu('&File')

        #File Inputs
        file.addAction(new)
        file.addAction(open)
        file.addAction(save)
        file.addAction(prints)
        file.addSeparator()
        file.addAction(quit)

        #Cut Input
        cut = QtGui.QAction("&Cut", self)
        cut.setShortcut("Ctrl+X")
        cut.triggered.connect(self.Cut)

        #Copy Input
        copy = QtGui.QAction("&Copy", self)
        copy.setShortcut("Ctrl+C")
        copy.triggered.connect(self.Copy)

        #Paste Input
        paste = QtGui.QAction("&Paste", self)
        paste.setShortcut("Ctrl+V")
        paste.triggered.connect(self.Paste)

        #Undo Input
        undo = QtGui.QAction("&Undo", self)
        undo.setShortcut("Ctrl+Z")
        undo.triggered.connect(self.Undo)

        #Redo Input
        redo = QtGui.QAction("&Redo", self)
        redo.setShortcut("Ctrl+Y")
        redo.triggered.connect(self.Redo)

        #Edit Menubar
        edit = menubar.addMenu('&Edit')

        #Edit Inputs
        edit.addAction(cut)
        edit.addAction(copy)
        edit.addAction(paste)
        edit.addSeparator()
        edit.addAction(undo)
        edit.addAction(redo)

        #Fullscreen Input
        fullscreen = QtGui.QAction("&Fullscreen", self)
        fullscreen.setShortcut("F11")
        fullscreen.triggered.connect(self.Fullscreen)

        #Align Left Input
        align_left = QtGui.QAction("&Align Left", self)
        align_left.triggered.connect(self.Align_Left)

        #Align Right Input
        align_right = QtGui.QAction("&Align Right", self)
        align_right.triggered.connect(self.Align_Right)

        #Align Center Input
        align_center = QtGui.QAction("&Align Center", self)
        align_center.triggered.connect(self.Align_Center)

        #Align Justify Input
        align_justify = QtGui.QAction("&Align Justify", self)
        align_justify.triggered.connect(self.Align_Justify)

        #View Menubar
        view = menubar.addMenu('&View')

        #View Inputs
        view.addAction(fullscreen)
        view.addSeparator()
        view.addAction(align_left)
        view.addAction(align_right)
        view.addAction(align_center)
        view.addAction(align_justify)

        #Font Family Input
        font_family = QtGui.QWidgetAction(self)
        font_family.setDefaultWidget(fontBox)

        #Settings Menubar
        settings = menubar.addMenu('&Settings')
        menu_font = settings.addMenu("&Font")
        menu_font.addAction(font_family)


        font_size = QtGui.QWidgetAction(self)
        font_size.setDefaultWidget(fontSize)
        menu_size = settings.addMenu("&Font Size")
        menu_size.addAction(font_size)

        self.toolbar()


    #Input Functions
    def New(self):
        self.text.clear()

    def Open(self):
        filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File')
        f = open(filename, 'r')
        filedata = f.read()
        self.text.setText(filedata)
        f.close()

    def Save(self):
        name = QtGui.QFileDialog.getSaveFileName(self, 'Save File')
        file = open(name,'w')
        text = self.textEdit.toPlainText()
        file.write(text)
        file.close()

    def Print(self):
        print_dialog = QtGui.QPrintDialog()
        if print_dialog.exec_() == QtGui.QDialog.Accepted:
            self.text.document().print_(print_dialog.printer())

    def Quit(self):
        sys.exit()

    def Undo(self):
        self.text.undo()

    def Redo(self):
        self.text.redo()

    def Cut(self):
        self.text.cut()

    def Copy(self):
        self.text.copy()

    def Paste(self):
        self.text.paste()

    def Align_Left(self):
        self.text.setAlignment(Qt.AlignLeft)

    def Align_Right(self):
        self.text.setAlignment(Qt.AlignRight)

    def Align_Center(self):
        self.text.setAlignment(Qt.AlignCenter)

    def Align_Justify(self):
        self.text.setAlignment(Qt.AlignJustify)

    def Fullscreen(self):
        if not self.isFullScreen():
            self.showFullScreen()
        else:
            self.showMaximized()

    def FontFamily(self,font):
        self.text.setCurrentFont(font)

    def FontSize(self, fontsize):
        self.text.setFontPointSize(int(fontsize))

    #Toolbar
    def toolbar(self):

        #New Tool
        new = QtGui.QAction(QtGui.QIcon('icons/new.png'), 'New', self)
        new.triggered.connect(self.New)

        #Open Tool
        open = QtGui.QAction(QtGui.QIcon('icons/open.png'), 'Open', self)
        open.triggered.connect(self.Open)

        #Save Tool
        save = QtGui.QAction(QtGui.QIcon('icons/save.png'), 'Save', self)
        save.triggered.connect(self.Save)

        #Print Tool
        prints = QtGui.QAction(QtGui.QIcon('icons/print.png'), 'Print', self)
        prints.triggered.connect(self.Print)

        #Quit Tool
        quit = QtGui.QAction(QtGui.QIcon('icons/quit.png'), 'Quit', self)
        quit.triggered.connect(self.Quit)

        #Cut Tool
        cut = QtGui.QAction(QtGui.QIcon('icons/cut.png'), 'Cut', self)
        cut.triggered.connect(self.Cut)

        #Copy Tool
        copy = QtGui.QAction(QtGui.QIcon('icons/copy.png'), 'Copy', self)
        copy.triggered.connect(self.Copy)

        #Paste Tool
        paste = QtGui.QAction(QtGui.QIcon('icons/paste.png'), 'Paste', self)
        paste.triggered.connect(self.Paste)

        #Undo Tool
        undo = QtGui.QAction(QtGui.QIcon('icons/undo.png'), 'Undo', self)
        undo.triggered.connect(self.Undo)

        #Redo Tool
        redo = QtGui.QAction(QtGui.QIcon('icons/redo.png'), 'Redo', self)
        redo.triggered.connect(self.Redo)

        #Toolbar Menu
        self.toolbar = self.addToolBar("Toolbar")
        self.toolbar.addAction(new)
        self.toolbar.addAction(open)
        self.toolbar.addAction(save)
        self.toolbar.addSeparator()
        self.toolbar.addAction(cut)
        self.toolbar.addAction(copy)
        self.toolbar.addAction(paste)
        self.toolbar.addSeparator()
        self.toolbar.addAction(undo)
        self.toolbar.addAction(redo)
        self.toolbar.addSeparator()
        self.toolbar.addAction(prints)
        self.toolbar.addSeparator()
        self.toolbar.addAction(quit)

        #Reveals The Toolbar
        self.show()

#Run Function
def run():
    app = QtGui.QApplication(sys.argv)
    GUI = Window()
    sys.exit(app.exec_())


run()

I attempted to use the answer provided by Drewness and plug it into my code but I got this error:

TypeError: 'QTextEdit' object is not callable


Solution

  • First of all, having a lot does not help to have a legible code, so I took the liberty of reducing it and ordering it.

    You must set a QTabWidget as centralWidget, and in each tab create a QTextEdit, but you must have a current QTextEdit, which is changed when another tab is selected, for this you must use the currentChanged signal.

    All actions must be done to that QTextEdit, and in the case of new and open you have to create a QTextEdit, and fill it in if necessary.

    import os
    import sys
    from PyQt4 import QtGui, QtCore
    
    class Window(QtGui.QMainWindow):
        def __init__(self):
            super(Window, self).__init__()
            self.showMaximized()
            self.setWindowTitle("Editory")
            self.setWindowIcon(QtGui.QIcon('favicon.png'))
    
            self.current_editor = self.create_editor()
            self.editors = []
    
            self.tab_widget = QtGui.QTabWidget()
            self.tab_widget.setTabsClosable(True)
            self.tab_widget.currentChanged.connect(self.change_text_editor)
            self.tab_widget.tabCloseRequested.connect(self.remove_editor)
            self.new_document()
            self.setCentralWidget(self.tab_widget)
    
            self.configure_menuBar()
            self.configure_toolbar()
    
        def configure_menuBar(self):
            menubar = self.menuBar()
    
            menubar_items = {
                '&File': [
                    ("&New", "Ctrl+N", self.new_document),
                    ("&Open", "Ctrl+O", self.open_document),
                    ("&Save", "Ctrl+S", self.save_document),
                    ("&Print", "Ctrl+P", self.print_document),
                    None,
                    ("&Quit", "Ctrl+Q", self.quit),
                ],
                '&Edit': [
                    ("&Cut", "Ctrl+X", self.cut_document),
                    ("&Copy", "Ctrl+C", self.copy_document),
                    ("&Paste", "Ctrl+V", self.paste_document),
                    None,
                    ("&Undo", "Ctrl+Z", self.undo_document),
                    ("&Redo", "Ctrl+Y", self.redo_document)
                ],
                '&View': [
                    ("&Fullscreen", "F11", self.fullscreen),
                    None,
                    ("&Align Left", "", self.align_left),
                    ("&Align Right", "", self.align_right),
                    ("&Align Center", "", self.align_center),
                    ("&Align Justify", "", self.align_justify)
                ]
            }
    
            for menuitem, actions in menubar_items.items():
                menu = menubar.addMenu(menuitem)
                for act in actions:
                    if act:
                        text, shorcut, callback = act
                        action = QtGui.QAction(text, self)
                        action.setShortcut(shorcut)
                        action.triggered.connect(callback)
                        menu.addAction(action)
                    else :
                        menu.addSeparator()
    
            # Font Family Input
            fontBox = QtGui.QFontComboBox(self)
            fontBox.currentFontChanged.connect(self.FontFamily)
    
            fontSize = QtGui.QComboBox(self)
            fontSize.setEditable(True)
            fontSize.setMinimumContentsLength(3)
    
            fontSize.activated.connect(self.FontSize)
    
            # Font Sizes
            fontSizes = ['6', '7', '8', '9', '10', '11', '12', '13', '14',
                '15', '16', '18', '20', '22', '24', '26', '28',
                '32', '36', '40', '44', '48', '54', '60', '66',
                '72', '80', '88', '96'
            ]
    
            fontSize.addItems(fontSizes)
            font_family = QtGui.QWidgetAction(self)
            font_family.setDefaultWidget(fontBox)
            # Settings Menubar
            settings = menubar.addMenu('&Settings')
            menu_font = settings.addMenu("&Font")
            menu_font.addAction(font_family)
    
            font_size = QtGui.QWidgetAction(self)
            font_size.setDefaultWidget(fontSize)
            menu_size = settings.addMenu("&Font Size")
            menu_size.addAction(font_size)
    
        def configure_toolbar(self):
            items = (('icons/new.png', 'New', self.new_document),
                ('icons/open.png', 'Open', self.open_document),
                ('icons/save.png', 'Save', self.save_document),
                None,
                ('icons/cut.png', 'Cut', self.cut_document),
                ('icons/copy.png', 'Copy', self.copy_document),
                ('icons/paste.png', 'Paste', self.paste_document),
                None,
                ('icons/undo.png', 'Undo', self.undo_document),
                ('icons/redo.png', 'Redo', self.redo_document),
                None,
                ('icons/print.png', 'Print', self.print_document),
                None,
                ('icons/quit.png', 'Quit', self.quit),
            )
    
            self.toolbar = self.addToolBar("Toolbar")
    
            for item in items:
                if item:
                    icon, text, callback = item
                    action = QtGui.QAction(QtGui.QIcon(icon), text, self)
                    action.triggered.connect(callback)
                    self.toolbar.addAction(action)
                else :
                    self.toolbar.addSeparator()
    
        def remove_editor(self, index):
            self.tab_widget.removeTab(index)
            if index < len(self.editors):
                del self.editors[index]
    
        def create_editor(self):
            text_editor = QtGui.QTextEdit()
            text_editor.setTabStopWidth(12)
            return text_editor
    
        def change_text_editor(self, index):
            if index < len(self.editors):
                self.current_editor = self.editors[index]
    
        # Input Functions
        def new_document(self, checked = False, title = "Untitled"):
            self.current_editor = self.create_editor()
            self.editors.append(self.current_editor)
            self.tab_widget.addTab(self.current_editor, title + str(len(self.editors)))
            self.tab_widget.setCurrentWidget(self.current_editor)
    
        def open_document(self):
            filename = QtGui.QFileDialog.getOpenFileName(self, 'Open File')
            if filename:
                f = open(filename, 'r')
            filedata = f.read()
            self.new_document(title = filename)
            self.current_editor.setText(filedata)
            f.close()
    
        def save_document(self):
            name = QtGui.QFileDialog.getSaveFileName(self, 'Save File')
            file = open(name, 'w')
            if file:
                text = self.current_editor.toPlainText()
                file.write(text)
                file.close()
    
        def print_document(self):
            print_dialog = QtGui.QPrintDialog()
            if print_dialog.exec_() == QtGui.QDialog.Accepted:
                self.current_editor.document().print_(print_dialog.printer())
    
        def quit(self): self.close()
    
        def undo_document(self): self.current_editor.undo()
    
        def redo_document(self): self.current_editor.redo()
    
        def cut_document(self): self.current_editor.cut()
    
        def copy_document(self): self.current_editor.copy()
    
        def paste_document(self): self.current_editor.paste()
    
        def align_left(self): self.current_editor.setAlignment(Qt.AlignLeft)
    
        def align_right(self): self.current_editor.setAlignment(Qt.AlignRight)
    
        def align_center(self): self.current_editor.setAlignment(Qt.AlignCenter)
    
        def align_justify(self):
            self.current_editor.setAlignment(Qt.AlignJustify)
    
        def fullscreen(self):
            if not self.isFullScreen():
                self.showFullScreen()
            else :
                self.showMaximized()
    
        def FontFamily(self, font):
            self.current_editor.setCurrentFont(font)
    
        def FontSize(self, fontsize):
            self.current_editor.setFontPointSize(int(fontsize))
    
    def run():
        app = QtGui.QApplication(sys.argv)
        GUI = Window()
        sys.exit(app.exec_())
    
    run()