Example #1
0
 def createEditor(self, parent, option, index):
     dateedit = QDateEdit(parent)
     #dateedit=QDateTimeEdit(parent)
     dateedit.setDateRange(self.minimum, self.maximum)
     dateedit.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
     dateedit.setDisplayFormat(self.format)
     dateedit.setCalendarPopup(True)
     return dateedit
class 시간날짜편집기(QWidget):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        label = QLabel('QTimeEdit')
        label.setAlignment(Qt.AlignCenter)

        time = QTimeEdit(self)
        time.setTime(QTime.currentTime())
        time.setTimeRange(QTime(00, 00, 00), QTime.currentTime())
        time.setDisplayFormat('a:hh:mm:ss.zzz')

        label2 = QLabel('QDateEdit')
        label2.setAlignment(Qt.AlignCenter)

        self.date_edit = QDateEdit(self)
        self.date_edit.setDate(QDate.currentDate())
        self.date_edit.setDateRange(QDate(2000, 1, 1), QDate.currentDate())
        # self.date_edit.setDisplayFormat('yyyy년 MMMM d일')
        self.date_edit.dateChanged.connect(self.dateChange)

        self.label3 = QLabel('이곳에 QDateEdit에서 선택된 값이 나타납니다.')
        self.label3.setAlignment(Qt.AlignCenter)

        label4 = QLabel('QDateTimeEdit')
        label4.setAlignment(Qt.AlignCenter)

        label5 = QLabel(self)
        label5.setAlignment(Qt.AlignCenter)
        label5.setText(
            f'QDateTime \n 현재 시간은 {QDateTime.currentDateTime().toString("yyyy년 MMMM d일 ap hh시 mm분 ss초.zzz")} 입니다.'
        )

        dt_edit = QDateTimeEdit(self)
        dt_edit.setDateTimeRange(QDateTime(2020, 1, 1, 00, 00, 00),\
                                 QDateTime(2021, 1, 1, 00, 00, 00))
        dt_edit.setDisplayFormat('yyyy.MM.dd hh:mm:ss')

        vbox = QVBoxLayout()
        vbox.addWidget(label)
        vbox.addWidget(time)
        vbox.addWidget(label2)
        vbox.addWidget(self.date_edit)
        vbox.addWidget(self.label3)
        vbox.addWidget(label4)
        vbox.addWidget(label5)
        vbox.addWidget(dt_edit)

        self.setLayout(vbox)

        self.setWindowTitle('QTime, QDateEdit, QDateTimeEdit')
        self.setGeometry(300, 300, 400, 300)
        self.show()

    def dateChange(self):
        self.label3.setText(self.date_edit.date().toString('yyyy년 MMMM d일'))
Example #3
0
    def createDateTimeEdits(self):
        self.editsGroup = QGroupBox("Date and time spin boxes")

        dateLabel = QLabel()
        dateEdit = QDateEdit(QDate.currentDate())
        dateEdit.setDateRange(QDate(2005, 1, 1), QDate(2010, 12, 31))
        dateLabel.setText("Appointment date (between %s and %s):" %
                    (dateEdit.minimumDate().toString(Qt.ISODate),
                    dateEdit.maximumDate().toString(Qt.ISODate)))

        timeLabel = QLabel()
        timeEdit = QTimeEdit(QTime.currentTime())
        timeEdit.setTimeRange(QTime(9, 0, 0, 0), QTime(16, 30, 0, 0))
        timeLabel.setText("Appointment time (between %s and %s):" %
                    (timeEdit.minimumTime().toString(Qt.ISODate),
                    timeEdit.maximumTime().toString(Qt.ISODate)))

        self.meetingLabel = QLabel()
        self.meetingEdit = QDateTimeEdit(QDateTime.currentDateTime())

        formatLabel = QLabel("Format string for the meeting date and time:")

        formatComboBox = QComboBox()
        formatComboBox.addItem('yyyy-MM-dd hh:mm:ss (zzz \'ms\')')
        formatComboBox.addItem('hh:mm:ss MM/dd/yyyy')
        formatComboBox.addItem('hh:mm:ss dd/MM/yyyy')
        formatComboBox.addItem('hh:mm:ss')
        formatComboBox.addItem('hh:mm ap')

        formatComboBox.activated[str].connect(self.setFormatString)

        self.setFormatString(formatComboBox.currentText())

        editsLayout = QVBoxLayout()
        editsLayout.addWidget(dateLabel)
        editsLayout.addWidget(dateEdit)
        editsLayout.addWidget(timeLabel)
        editsLayout.addWidget(timeEdit)
        editsLayout.addWidget(self.meetingLabel)
        editsLayout.addWidget(self.meetingEdit)
        editsLayout.addWidget(formatLabel)
        editsLayout.addWidget(formatComboBox)
        self.editsGroup.setLayout(editsLayout)
Example #4
0
    def createDateTimeEdits(self):
        self.editsGroup = QGroupBox("Date and time spin boxes")

        dateLabel = QLabel()
        dateEdit = QDateEdit(QDate.currentDate())
        dateEdit.setDateRange(QDate(2005, 1, 1), QDate(2010, 12, 31))
        dateLabel.setText("Appointment date (between %s and %s):" %
                          (dateEdit.minimumDate().toString(Qt.ISODate),
                           dateEdit.maximumDate().toString(Qt.ISODate)))

        timeLabel = QLabel()
        timeEdit = QTimeEdit(QTime.currentTime())
        timeEdit.setTimeRange(QTime(9, 0, 0, 0), QTime(16, 30, 0, 0))
        timeLabel.setText("Appointment time (between %s and %s):" %
                          (timeEdit.minimumTime().toString(Qt.ISODate),
                           timeEdit.maximumTime().toString(Qt.ISODate)))

        self.meetingLabel = QLabel()
        self.meetingEdit = QDateTimeEdit(QDateTime.currentDateTime())

        formatLabel = QLabel("Format string for the meeting date and time:")

        formatComboBox = QComboBox()
        formatComboBox.addItem('yyyy-MM-dd hh:mm:ss (zzz \'ms\')')
        formatComboBox.addItem('hh:mm:ss MM/dd/yyyy')
        formatComboBox.addItem('hh:mm:ss dd/MM/yyyy')
        formatComboBox.addItem('hh:mm:ss')
        formatComboBox.addItem('hh:mm ap')

        formatComboBox.activated[str].connect(self.setFormatString)

        self.setFormatString(formatComboBox.currentText())

        editsLayout = QVBoxLayout()
        editsLayout.addWidget(dateLabel)
        editsLayout.addWidget(dateEdit)
        editsLayout.addWidget(timeLabel)
        editsLayout.addWidget(timeEdit)
        editsLayout.addWidget(self.meetingLabel)
        editsLayout.addWidget(self.meetingEdit)
        editsLayout.addWidget(formatLabel)
        editsLayout.addWidget(formatComboBox)
        self.editsGroup.setLayout(editsLayout)
Example #5
0
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()

        self.createPreviewGroupBox()
        self.createGeneralOptionsGroupBox()
        self.createDatesGroupBox()
        self.createTextFormatsGroupBox()

        layout = QGridLayout()
        layout.addWidget(self.previewGroupBox, 0, 0)
        layout.addWidget(self.generalOptionsGroupBox, 0, 1)
        layout.addWidget(self.datesGroupBox, 1, 0)
        layout.addWidget(self.textFormatsGroupBox, 1, 1)
        layout.setSizeConstraint(QLayout.SetFixedSize)
        self.setLayout(layout)

        self.previewLayout.setRowMinimumHeight(
            0,
            self.calendar.sizeHint().height())
        self.previewLayout.setColumnMinimumWidth(
            0,
            self.calendar.sizeHint().width())

        self.setWindowTitle("Calendar Widget")

    def localeChanged(self, index):
        self.calendar.setLocale(self.localeCombo.itemData(index))

    def firstDayChanged(self, index):
        self.calendar.setFirstDayOfWeek(
            Qt.DayOfWeek(self.firstDayCombo.itemData(index)))

    def selectionModeChanged(self, index):
        self.calendar.setSelectionMode(
            QCalendarWidget.SelectionMode(
                self.selectionModeCombo.itemData(index)))

    def horizontalHeaderChanged(self, index):
        self.calendar.setHorizontalHeaderFormat(
            QCalendarWidget.HorizontalHeaderFormat(
                self.horizontalHeaderCombo.itemData(index)))

    def verticalHeaderChanged(self, index):
        self.calendar.setVerticalHeaderFormat(
            QCalendarWidget.VerticalHeaderFormat(
                self.verticalHeaderCombo.itemData(index)))

    def selectedDateChanged(self):
        self.currentDateEdit.setDate(self.calendar.selectedDate())

    def minimumDateChanged(self, date):
        self.calendar.setMinimumDate(date)
        self.maximumDateEdit.setDate(self.calendar.maximumDate())

    def maximumDateChanged(self, date):
        self.calendar.setMaximumDate(date)
        self.minimumDateEdit.setDate(self.calendar.minimumDate())

    def weekdayFormatChanged(self):
        format = QTextCharFormat()
        format.setForeground(
            Qt.GlobalColor(
                self.weekdayColorCombo.itemData(
                    self.weekdayColorCombo.currentIndex())))

        self.calendar.setWeekdayTextFormat(Qt.Monday, format)
        self.calendar.setWeekdayTextFormat(Qt.Tuesday, format)
        self.calendar.setWeekdayTextFormat(Qt.Wednesday, format)
        self.calendar.setWeekdayTextFormat(Qt.Thursday, format)
        self.calendar.setWeekdayTextFormat(Qt.Friday, format)

    def weekendFormatChanged(self):
        format = QTextCharFormat()
        format.setForeground(
            Qt.GlobalColor(
                self.weekendColorCombo.itemData(
                    self.weekendColorCombo.currentIndex())))

        self.calendar.setWeekdayTextFormat(Qt.Saturday, format)
        self.calendar.setWeekdayTextFormat(Qt.Sunday, format)

    def reformatHeaders(self):
        text = self.headerTextFormatCombo.currentText()
        format = QTextCharFormat()

        if text == "Bold":
            format.setFontWeight(QFont.Bold)
        elif text == "Italic":
            format.setFontItalic(True)
        elif text == "Green":
            format.setForeground(Qt.green)

        self.calendar.setHeaderTextFormat(format)

    def reformatCalendarPage(self):
        if self.firstFridayCheckBox.isChecked():
            firstFriday = QDate(self.calendar.yearShown(),
                                self.calendar.monthShown(), 1)

            while firstFriday.dayOfWeek() != Qt.Friday:
                firstFriday = firstFriday.addDays(1)

            firstFridayFormat = QTextCharFormat()
            firstFridayFormat.setForeground(Qt.blue)

            self.calendar.setDateTextFormat(firstFriday, firstFridayFormat)

        # May 1st in Red takes precedence.
        if self.mayFirstCheckBox.isChecked():
            mayFirst = QDate(self.calendar.yearShown(), 5, 1)

            mayFirstFormat = QTextCharFormat()
            mayFirstFormat.setForeground(Qt.red)

            self.calendar.setDateTextFormat(mayFirst, mayFirstFormat)

    def createPreviewGroupBox(self):
        self.previewGroupBox = QGroupBox("Preview")

        self.calendar = QCalendarWidget()
        self.calendar.setMinimumDate(QDate(1900, 1, 1))
        self.calendar.setMaximumDate(QDate(3000, 1, 1))
        self.calendar.setGridVisible(True)
        self.calendar.currentPageChanged.connect(self.reformatCalendarPage)

        self.previewLayout = QGridLayout()
        self.previewLayout.addWidget(self.calendar, 0, 0, Qt.AlignCenter)
        self.previewGroupBox.setLayout(self.previewLayout)

    def createGeneralOptionsGroupBox(self):
        self.generalOptionsGroupBox = QGroupBox("General Options")

        self.localeCombo = QComboBox()

        curLocaleIndex = -1
        index = 0

        this_language = self.locale().nativeLanguageName()
        this_country = self.locale().nativeCountryName()

        for locale in QLocale.matchingLocales(QLocale.AnyLanguage,
                                              QLocale.AnyScript,
                                              QLocale.AnyCountry):
            language = locale.nativeLanguageName()
            country = locale.nativeCountryName()

            if language == this_language and country == this_country:
                curLocaleIndex = index

            self.localeCombo.addItem('%s/%s' % (language, country), locale)
            index += 1

        if curLocaleIndex != -1:
            self.localeCombo.setCurrentIndex(curLocaleIndex)

        self.localeLabel = QLabel("&Locale")
        self.localeLabel.setBuddy(self.localeCombo)

        self.firstDayCombo = QComboBox()
        self.firstDayCombo.addItem("Sunday", Qt.Sunday)
        self.firstDayCombo.addItem("Monday", Qt.Monday)
        self.firstDayCombo.addItem("Tuesday", Qt.Tuesday)
        self.firstDayCombo.addItem("Wednesday", Qt.Wednesday)
        self.firstDayCombo.addItem("Thursday", Qt.Thursday)
        self.firstDayCombo.addItem("Friday", Qt.Friday)
        self.firstDayCombo.addItem("Saturday", Qt.Saturday)

        self.firstDayLabel = QLabel("Wee&k starts on:")
        self.firstDayLabel.setBuddy(self.firstDayCombo)

        self.selectionModeCombo = QComboBox()
        self.selectionModeCombo.addItem("Single selection",
                                        QCalendarWidget.SingleSelection)
        self.selectionModeCombo.addItem("None", QCalendarWidget.NoSelection)
        self.selectionModeLabel = QLabel("&Selection mode:")
        self.selectionModeLabel.setBuddy(self.selectionModeCombo)

        self.gridCheckBox = QCheckBox("&Grid")
        self.gridCheckBox.setChecked(self.calendar.isGridVisible())

        self.navigationCheckBox = QCheckBox("&Navigation bar")
        self.navigationCheckBox.setChecked(True)

        self.horizontalHeaderCombo = QComboBox()
        self.horizontalHeaderCombo.addItem(
            "Single letter day names", QCalendarWidget.SingleLetterDayNames)
        self.horizontalHeaderCombo.addItem("Short day names",
                                           QCalendarWidget.ShortDayNames)
        self.horizontalHeaderCombo.addItem("Long day names",
                                           QCalendarWidget.LongDayNames)
        self.horizontalHeaderCombo.addItem("None",
                                           QCalendarWidget.NoHorizontalHeader)
        self.horizontalHeaderCombo.setCurrentIndex(1)

        self.horizontalHeaderLabel = QLabel("&Horizontal header:")
        self.horizontalHeaderLabel.setBuddy(self.horizontalHeaderCombo)

        self.verticalHeaderCombo = QComboBox()
        self.verticalHeaderCombo.addItem("ISO week numbers",
                                         QCalendarWidget.ISOWeekNumbers)
        self.verticalHeaderCombo.addItem("None",
                                         QCalendarWidget.NoVerticalHeader)

        self.verticalHeaderLabel = QLabel("&Vertical header:")
        self.verticalHeaderLabel.setBuddy(self.verticalHeaderCombo)

        self.localeCombo.currentIndexChanged.connect(self.localeChanged)
        self.firstDayCombo.currentIndexChanged.connect(self.firstDayChanged)
        self.selectionModeCombo.currentIndexChanged.connect(
            self.selectionModeChanged)
        self.gridCheckBox.toggled.connect(self.calendar.setGridVisible)
        self.navigationCheckBox.toggled.connect(
            self.calendar.setNavigationBarVisible)
        self.horizontalHeaderCombo.currentIndexChanged.connect(
            self.horizontalHeaderChanged)
        self.verticalHeaderCombo.currentIndexChanged.connect(
            self.verticalHeaderChanged)

        checkBoxLayout = QHBoxLayout()
        checkBoxLayout.addWidget(self.gridCheckBox)
        checkBoxLayout.addStretch()
        checkBoxLayout.addWidget(self.navigationCheckBox)

        outerLayout = QGridLayout()
        outerLayout.addWidget(self.localeLabel, 0, 0)
        outerLayout.addWidget(self.localeCombo, 0, 1)
        outerLayout.addWidget(self.firstDayLabel, 1, 0)
        outerLayout.addWidget(self.firstDayCombo, 1, 1)
        outerLayout.addWidget(self.selectionModeLabel, 2, 0)
        outerLayout.addWidget(self.selectionModeCombo, 2, 1)
        outerLayout.addLayout(checkBoxLayout, 3, 0, 1, 2)
        outerLayout.addWidget(self.horizontalHeaderLabel, 4, 0)
        outerLayout.addWidget(self.horizontalHeaderCombo, 4, 1)
        outerLayout.addWidget(self.verticalHeaderLabel, 5, 0)
        outerLayout.addWidget(self.verticalHeaderCombo, 5, 1)
        self.generalOptionsGroupBox.setLayout(outerLayout)

        self.firstDayChanged(self.firstDayCombo.currentIndex())
        self.selectionModeChanged(self.selectionModeCombo.currentIndex())
        self.horizontalHeaderChanged(self.horizontalHeaderCombo.currentIndex())
        self.verticalHeaderChanged(self.verticalHeaderCombo.currentIndex())

    def createDatesGroupBox(self):
        self.datesGroupBox = QGroupBox(self.tr("Dates"))

        self.minimumDateEdit = QDateEdit()
        self.minimumDateEdit.setDisplayFormat('MMM d yyyy')
        self.minimumDateEdit.setDateRange(self.calendar.minimumDate(),
                                          self.calendar.maximumDate())
        self.minimumDateEdit.setDate(self.calendar.minimumDate())

        self.minimumDateLabel = QLabel("&Minimum Date:")
        self.minimumDateLabel.setBuddy(self.minimumDateEdit)

        self.currentDateEdit = QDateEdit()
        self.currentDateEdit.setDisplayFormat('MMM d yyyy')
        self.currentDateEdit.setDate(self.calendar.selectedDate())
        self.currentDateEdit.setDateRange(self.calendar.minimumDate(),
                                          self.calendar.maximumDate())

        self.currentDateLabel = QLabel("&Current Date:")
        self.currentDateLabel.setBuddy(self.currentDateEdit)

        self.maximumDateEdit = QDateEdit()
        self.maximumDateEdit.setDisplayFormat('MMM d yyyy')
        self.maximumDateEdit.setDateRange(self.calendar.minimumDate(),
                                          self.calendar.maximumDate())
        self.maximumDateEdit.setDate(self.calendar.maximumDate())

        self.maximumDateLabel = QLabel("Ma&ximum Date:")
        self.maximumDateLabel.setBuddy(self.maximumDateEdit)

        self.currentDateEdit.dateChanged.connect(self.calendar.setSelectedDate)
        self.calendar.selectionChanged.connect(self.selectedDateChanged)
        self.minimumDateEdit.dateChanged.connect(self.minimumDateChanged)
        self.maximumDateEdit.dateChanged.connect(self.maximumDateChanged)

        dateBoxLayout = QGridLayout()
        dateBoxLayout.addWidget(self.currentDateLabel, 1, 0)
        dateBoxLayout.addWidget(self.currentDateEdit, 1, 1)
        dateBoxLayout.addWidget(self.minimumDateLabel, 0, 0)
        dateBoxLayout.addWidget(self.minimumDateEdit, 0, 1)
        dateBoxLayout.addWidget(self.maximumDateLabel, 2, 0)
        dateBoxLayout.addWidget(self.maximumDateEdit, 2, 1)
        dateBoxLayout.setRowStretch(3, 1)

        self.datesGroupBox.setLayout(dateBoxLayout)

    def createTextFormatsGroupBox(self):
        self.textFormatsGroupBox = QGroupBox("Text Formats")

        self.weekdayColorCombo = self.createColorComboBox()
        self.weekdayColorCombo.setCurrentIndex(
            self.weekdayColorCombo.findText("Black"))

        self.weekdayColorLabel = QLabel("&Weekday color:")
        self.weekdayColorLabel.setBuddy(self.weekdayColorCombo)

        self.weekendColorCombo = self.createColorComboBox()
        self.weekendColorCombo.setCurrentIndex(
            self.weekendColorCombo.findText("Red"))

        self.weekendColorLabel = QLabel("Week&end color:")
        self.weekendColorLabel.setBuddy(self.weekendColorCombo)

        self.headerTextFormatCombo = QComboBox()
        self.headerTextFormatCombo.addItem("Bold")
        self.headerTextFormatCombo.addItem("Italic")
        self.headerTextFormatCombo.addItem("Plain")

        self.headerTextFormatLabel = QLabel("&Header text:")
        self.headerTextFormatLabel.setBuddy(self.headerTextFormatCombo)

        self.firstFridayCheckBox = QCheckBox("&First Friday in blue")

        self.mayFirstCheckBox = QCheckBox("May &1 in red")

        self.weekdayColorCombo.currentIndexChanged.connect(
            self.weekdayFormatChanged)
        self.weekendColorCombo.currentIndexChanged.connect(
            self.weekendFormatChanged)
        self.headerTextFormatCombo.currentIndexChanged.connect(
            self.reformatHeaders)
        self.firstFridayCheckBox.toggled.connect(self.reformatCalendarPage)
        self.mayFirstCheckBox.toggled.connect(self.reformatCalendarPage)

        checkBoxLayout = QHBoxLayout()
        checkBoxLayout.addWidget(self.firstFridayCheckBox)
        checkBoxLayout.addStretch()
        checkBoxLayout.addWidget(self.mayFirstCheckBox)

        outerLayout = QGridLayout()
        outerLayout.addWidget(self.weekdayColorLabel, 0, 0)
        outerLayout.addWidget(self.weekdayColorCombo, 0, 1)
        outerLayout.addWidget(self.weekendColorLabel, 1, 0)
        outerLayout.addWidget(self.weekendColorCombo, 1, 1)
        outerLayout.addWidget(self.headerTextFormatLabel, 2, 0)
        outerLayout.addWidget(self.headerTextFormatCombo, 2, 1)
        outerLayout.addLayout(checkBoxLayout, 3, 0, 1, 2)
        self.textFormatsGroupBox.setLayout(outerLayout)

        self.weekdayFormatChanged()
        self.weekendFormatChanged()

        self.reformatHeaders()
        self.reformatCalendarPage()

    def createColorComboBox(self):
        comboBox = QComboBox()
        comboBox.addItem("Red", Qt.red)
        comboBox.addItem("Blue", Qt.blue)
        comboBox.addItem("Black", Qt.black)
        comboBox.addItem("Magenta", Qt.magenta)

        return comboBox
Example #6
0
class ViewDataWindow(QDialog):
    formSubmitted = pyqtSignal()
    closeSignal = pyqtSignal()

    def __init__(self, LOGIN, parent=None):
        #super(ViewDataWindow, self).__init__(parent)
        super().__init__(parent)
        self.LOGIN = LOGIN
        self.db = db(self.LOGIN, "Brewing")
        self.displayNo = 0
        self.displayedBrewsH = []
        self.displayedBrewsVMash = []
        self.displayedBrewsVBoil = []
        self.displayedBrewsVFerment = []
        self.create_layout_viewData()
        self.setWindowTitle('Past Brew Viewer')
        self.activeColours = []
        self.colours = ["red", "green", "blue", "black",\
                        "cyan", "magenta", "yellow", "gray"]

    # Function to create layout of New Brew window
    def create_layout_viewData(self):

        # Create scroll boxes for filtering data
        filterGroupBox = QGroupBox("Filter by:")

        # Date edit box
        lab_date = QLabel("Date:")
        self.dateEdit = QDateEdit()
        # Set range of possible dates, current date is max date
        self.maxDate = QDate().currentDate()
        self.minDate = QDate(2019, 1, 1)
        self.dateEdit.setDate(self.maxDate)
        self.dateEdit.setDateRange(self.minDate, self.maxDate)
        self.dateEdit.setCalendarPopup(1)
        self.dateEdit.setDisplayFormat("dd/MM/yy")
        #self.dateEdit2 = QLineEdit()
        self.dateEdit.dateChanged.connect(self.filter_date)

        dateHLayout = QHBoxLayout()
        dateHLayout.addWidget(lab_date)
        dateHLayout.addWidget(self.dateEdit)

        ### Text edit filters ###
        # Batch ID search
        lab_batch = QLabel("Batch ID:")
        self.edit_batchID = QLineEdit()
        self.edit_batchID.setPlaceholderText("Enter Batch ID")
        self.but_IDsearch = QPushButton("Go")
        self.but_IDsearch.setAutoDefault(0)
        self.but_IDsearch.clicked.connect(self.filter_batchID)
        self.edit_batchID.returnPressed.connect(self.filter_batchID)
        batchHLayout = QHBoxLayout()
        batchHLayout.addWidget(lab_batch)
        batchHLayout.addWidget(self.edit_batchID)
        batchHLayout.addWidget(self.but_IDsearch)

        # Recipe search
        lab_recipe = QLabel("Recipe:")
        self.lineEdit_recipe = QLineEdit()
        self.lineEdit_recipe.setPlaceholderText("Enter Recipe")
        self.lineEdit_recipe.textChanged.connect(self.filter_recipe)
        self.lineEdit_recipe.returnPressed.connect(self.filter_recipe)
        recipeHLayout = QHBoxLayout()
        recipeHLayout.addWidget(lab_recipe)
        recipeHLayout.addWidget(self.lineEdit_recipe)

        # Clear filters button
        self.but_clearFilter = QPushButton("Clear Filters")
        self.but_clearFilter.setAutoDefault(0)
        clearHLayout = QHBoxLayout()
        clearHLayout.addStretch(1)
        clearHLayout.addWidget(self.but_clearFilter)
        clearHLayout.addStretch(0)
        self.but_clearFilter.clicked.connect(self.clearFilters)

        # Filter groupbox layout

        #recipeHLayout.addWidget(self.recipeEdit)
        #recipeVLayout = QVBoxLayout()
        #recipeVLayout.addLayout(recipeHLayout)
        #recipeVLayout.addWidget(self.lineEdit_recipe)
        filterHLayout = QHBoxLayout()
        filterHLayout.addStretch(1)
        filterHLayout.addWidget(lab_date)
        filterHLayout.addWidget(self.dateEdit)
        filterHLayout.addStretch(1)
        #filterHLayout.addLayout(recipeVLayout)
        filterHLayout.addStretch(1)
        filterHLayout.addWidget(self.edit_batchID)
        filterHLayout.addWidget(self.but_IDsearch)
        filterHLayout.addStretch(1)
        #filterGroupBox.setLayout(filterHLayout)

        # Alternate - Filter vertical layout
        filterVLayout = QVBoxLayout()
        filterVLayout.addLayout(batchHLayout)
        filterVLayout.addLayout(recipeHLayout)
        filterVLayout.addLayout(dateHLayout)
        filterVLayout.addLayout(clearHLayout)
        filterGroupBox.setLayout(filterVLayout)

        # scrollHLayout = QHBoxLayout()
        # scrollHLayout.addWidget(filterGroupBox)
        # scrollHLayout.addStretch(1)

        # Create QTableView of brew data
        header = ['Brew ID', 'Recipe', 'Date']
        self.model = MyTableModel(
            self.db.readFromTable("Brews", "id, Recipe, Date"), header, self)
        self.proxyModel = QSortFilterProxyModel(self)
        self.proxyModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
        self.proxyModel.setSourceModel(self.model)
        self.dataTable = QTableView()
        self.dataTable.setModel(self.proxyModel)
        self.dataTable.setSortingEnabled(True)
        self.dataTable.setSelectionBehavior(1)

        # Create bottom buttons
        self.but_quit = QPushButton("Close")
        self.but_quit.setAutoDefault(0)
        self.but_view = QPushButton("Display Brew")
        self.but_view.setAutoDefault(0)
        quitHLayout = QHBoxLayout()
        quitHLayout.addStretch(0)
        quitHLayout.addWidget(self.but_quit)
        quitHLayout.addStretch(3)
        quitHLayout.addWidget(self.but_view)
        quitHLayout.addStretch(0)

        # Main vertical layout for left area
        lWidget = QWidget()
        vLayoutL = QVBoxLayout(lWidget)
        vLayoutL.addWidget(filterGroupBox)
        vLayoutL.addWidget(self.dataTable)
        vLayoutL.addLayout(quitHLayout)

        # Widget for displayed brews - Widget allows fixed height to be set
        displayedWidget = QWidget()
        #displayedWidget.setFixedHeight(180)
        # h Layout to add groupboxes of displayed brews - added to in viewButtonClicked slot
        self.hLayoutDisplayed = QHBoxLayout()
        self.hLayoutDisplayed.addStretch(1)
        self.hLayoutDisplayed.setSizeConstraint(5)
        displayedWidget.setLayout(self.hLayoutDisplayed)
        # Scroll area for horizontal displayed brews
        hScrollArea = QScrollArea()
        hScrollArea.setWidget(displayedWidget)
        hScrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        hScrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        #hScrollArea.setFixedHeight(120)
        hScrollArea.setMinimumHeight(20)
        # Main v layout for displayed brews widget
        displayTitle = QLabel("Displayed Brews:")
        displayTitle.setMaximumHeight(20)
        hDisplayedWidget = QWidget()
        self.vLayoutDisplayed = QVBoxLayout(hDisplayedWidget)
        self.vLayoutDisplayed.addWidget(displayTitle)
        self.vLayoutDisplayed.addWidget(hScrollArea)

        # Main vertical layout for right area
        rWidget = QWidget()
        rSplitter = QSplitter()
        rSplitter.setOrientation(Qt.Orientation(2))
        #vLayoutR = QVBoxLayout(rWidget)
        self.tabs = QTabWidget()
        self.tabMash = MashTab()
        self.tabBoil = BoilTab()
        self.tabFerment = FermentTab()
        self.tabs.resize(100, 1000)
        self.tabs.setMinimumSize(400, 100)
        self.tabs.addTab(self.tabMash, "Mash")
        self.tabs.addTab(self.tabBoil, "Boil")
        self.tabs.addTab(self.tabFerment, "Ferment")
        #vLayoutR.addLayout(self.vLayoutDisplayed)
        #vLayoutR.addWidget(self.tabs)
        rSplitter.addWidget(hDisplayedWidget)
        rSplitter.addWidget(self.tabs)

        # Main layout for whole window - splitter so widget sizes are adjustable
        mainLayout = QHBoxLayout()
        mainSplitter = QSplitter()
        mainSplitter.addWidget(lWidget)
        mainSplitter.addWidget(rSplitter)
        mainLayout.addWidget(mainSplitter)
        mainSplitter.setSizes([260, 740])

        self.setLayout(mainLayout)
        #self.showFullScreen()
        self.setGeometry(0, 0, 1500, 1000)

        self.but_view.clicked.connect(self.viewButtonClicked)
        self.but_view.clicked.connect(self.viewButtonClickedTabs)
        self.but_quit.clicked.connect(self.quitButtonClicked)

    def quitButtonClicked(self):

        self.close()
        self.closeSignal.emit()

    # Slot for adding selected brew to widget
    def viewButtonClicked(self):

        self.brewInfo = []  # array to place brew info: ID, Recipe, Date
        self.displayNo = self.displayNo + 1
        # Add brew info to array based on selected row
        index = (self.dataTable.selectionModel().currentIndex())
        for i in range(3):
            self.brewInfo.append(
                QLabel(str(index.sibling(index.row(), i).data())))

        # Choose colour to use for this displayed brew
        self.colourToUse = self.chooseColour()

        # Create group box with all brew info displayed and Remove button
        brewGroupBox = QGroupBox(str(self.displayNo))
        brewGroupBox.setObjectName("ColouredGroupBox")
        brewGroupBox.setStyleSheet(
            "QGroupBox#ColouredGroupBox { border: 2px solid %s;}" %
            self.colourToUse)
        brewForm = QFormLayout()
        brewForm.addRow(QLabel('Brew ID:'), self.brewInfo[0])
        brewForm.addRow(QLabel('Recipe:'), self.brewInfo[1])
        brewForm.addRow(QLabel('Date:'), self.brewInfo[2])
        removeButHLayout = QHBoxLayout()
        removeButHLayout.addStretch(1)
        self.but_Remove = QPushButton("Remove")
        removeButHLayout.addWidget(self.but_Remove)
        brewForm.addRow(removeButHLayout)
        brewGroupBox.setLayout(brewForm)
        # Add group box to layout - use insert so that stretch stays on right side
        self.hLayoutDisplayed.insertWidget(self.displayNo - 1, brewGroupBox)
        self.displayedBrewsH.append(
            brewGroupBox)  # Add groupbox to array of displayed brews
        # Signal to connect remove brew button. Lambda function used to pass argument of specific
        # brew to be removed
        self.but_Remove.clicked.connect(
            lambda: self.removeBrewClickedMash(brewGroupBox))
        self.but_Remove.clicked.connect(
            lambda: self.removeBrewClickedBoil(brewGroupBox))
        self.but_Remove.clicked.connect(
            lambda: self.removeBrewClickedFerment(brewGroupBox))
        self.but_Remove.clicked.connect(
            lambda: self.removeBrewClicked(brewGroupBox))

    # Slot for adding brew info to each of the process tabs
    def viewButtonClickedTabs(self):

        batchID = self.brewInfo[0].text()
        # Query database to get recipe data for the brew selected to view
        # brewInfo[0].text() gives brew ID for selected brew from table
        sql = f"SELECT * FROM Brews WHERE id = '{self.brewInfo[0].text()}'"
        query = self.db.custom(sql)

        self.recipedata = {}
        self.recipedata['batchID'] = query[0][0]
        self.recipedata['recipeName'] = query[0][1]
        self.recipedata['recipeDate'] = query[0][2]
        self.recipedata['mashTemp'] = query[0][3]
        self.recipedata['mashTime'] = query[0][4]
        self.recipedata['boilTemp'] = query[0][5]
        self.recipedata['boilTime'] = query[0][6]
        self.recipedata['hop1'] = (query[0][7], query[0][8])
        self.recipedata['hop2'] = (query[0][9], query[0][10])
        self.recipedata['hop3'] = (query[0][11], query[0][12])
        self.recipedata['hop4'] = (query[0][13], query[0][14])
        self.recipedata['fermenttemp'] = query[0][15]

        # Create groupboxes for each of the process tabs to fill with brew info
        mashGroupBox = QGroupBox(str(self.displayNo))
        mashGroupBox.setObjectName("MashColouredGroupBox")
        mashGroupBox.setStyleSheet(
            "QGroupBox#MashColouredGroupBox { border: 2px solid %s;}" %
            self.colourToUse)
        mashFormLayout = QFormLayout()
        mashFormLayout.addRow(
            QLabel(f"Temp ({DEGREES}C): {self.recipedata['mashTemp']}"))
        mashFormLayout.addRow(
            QLabel(f"Time (mins): {self.recipedata['mashTime']}"))
        mashGroupBox.setLayout(mashFormLayout)
        self.tabMash.mashVLayout.insertWidget(self.displayNo - 1, mashGroupBox)
        self.displayedBrewsVMash.append(mashGroupBox)

        boilGroupBox = QGroupBox(str(self.displayNo))
        boilGroupBox.setObjectName("BoilColouredGroupBox")
        boilGroupBox.setStyleSheet(
            "QGroupBox#BoilColouredGroupBox { border: 2px solid %s;}" %
            self.colourToUse)
        boilFormLayout = QFormLayout()
        boilFormLayout.addRow(
            QLabel(f"Temp ({DEGREES}C):{self.recipedata['boilTemp']}"))
        boilFormLayout.addRow(
            QLabel(f"Time (mins): {self.recipedata['boilTime']}"))
        boilFormLayout.addRow(QLabel(f"Hop 1: {self.recipedata['hop1'][0]}"))
        boilFormLayout.addRow(
            QLabel(f"Time (mins): {self.recipedata['hop1'][1]}"))
        boilFormLayout.addRow(QLabel(f"Hop 2: {self.recipedata['hop2'][0]}"))
        boilFormLayout.addRow(
            QLabel(f"Time (mins): {self.recipedata['hop2'][1]}"))
        boilFormLayout.addRow(QLabel(f"Hop 3: {self.recipedata['hop3'][0]}"))
        boilFormLayout.addRow(
            QLabel(f"Time (mins): {self.recipedata['hop3'][1]}"))
        boilFormLayout.addRow(QLabel(f"Hop 4: {self.recipedata['hop4'][0]}"))
        boilFormLayout.addRow(
            QLabel(f"Time (mins): {self.recipedata['hop4'][1]}"))
        boilGroupBox.setLayout(boilFormLayout)
        self.tabBoil.boilVLayout.insertWidget(self.displayNo - 1, boilGroupBox)
        self.displayedBrewsVBoil.append(boilGroupBox)

        fermentGroupBox = QGroupBox(str(self.displayNo))
        fermentGroupBox.setObjectName("FermentColouredGroupBox")
        fermentGroupBox.setStyleSheet(
            "QGroupBox#FermentColouredGroupBox { border: 2px solid %s;}" %
            self.colourToUse)
        fermentFormLayout = QFormLayout()
        fermentFormLayout.addRow(
            QLabel(f"Temp ({DEGREES}C): {self.recipedata['fermenttemp']}"))
        #fermentFormLayout.addRow(QLabel('Time (mins):'))
        fermentGroupBox.setLayout(fermentFormLayout)
        self.tabFerment.fermentVLayout.insertWidget(self.displayNo - 1,
                                                    fermentGroupBox)
        self.displayedBrewsVFerment.append(fermentGroupBox)

        ### PUTTING DATA ONTO GRAPHS ###
        # Query database to get data to plot on graphs
        sqlMash = f"SELECT TimeStamp, Temp FROM Mash WHERE BatchID = '{batchID}'"
        sqlBoil = f"SELECT TimeStamp, Temp FROM BoilMonitor WHERE BatchID = '{batchID}'"
        sqlFermentTemp = f"SELECT TimeStamp, Temp FROM Ferment WHERE BatchID = '{batchID}'"
        sqlFermentSG = f"SELECT TimeStamp, Sg FROM Ferment WHERE BatchID = '{batchID}'"
        mashDataX, mashDataY = self.createData(sqlMash)
        boilDataX, boilDataY = self.createData(sqlBoil)
        fermentTempDataX, fermentTempDataY = self.createData(sqlFermentTemp)
        fermentSGDataX, fermentSGDataY = self.createData(sqlFermentSG)

        # Create and add curves to each of the plots
        self.tabMash.graph.createCurve(mashDataX, mashDataY, self.colourToUse)
        self.tabBoil.graph.createCurve(boilDataX, boilDataY, self.colourToUse)
        self.tabFerment.tempGraph.createCurve(fermentTempDataX[1:],
                                              fermentTempDataY[1:],
                                              self.colourToUse)
        self.tabFerment.gravGraph.createCurve(fermentSGDataX[1:],
                                              fermentSGDataY[1:],
                                              self.colourToUse)

    # Function to choose first available colour
    def chooseColour(self):

        # Loop through dictionary, checking if self.colours[j] appear
        for colours in self.colours:
            # If it does appear, continue to next colour
            if colours not in self.activeColours:
                # If it doesn't appear, add colour to dictionary and return colour
                self.activeColours.append(colours)
                return colours

    # Get data from database using sql query
    def createData(self, sql):
        timestamps = []
        tempdat = []
        try:
            for data in self.db.custom(sql):
                timestamps.append(data[0])
                tempdat.append(data[1])

            startTime = timestamps[0]
            for i in range(len(timestamps)):
                timestamps[i] = (timestamps[i] - startTime).seconds
        except IndexError:
            return [0], [0]

        return timestamps, tempdat

    # Slot for removing group boxes from horizontal tab
    def removeBrewClicked(self, brewToRemove):

        brewArrayPos = self.displayedBrewsH.index(brewToRemove)

        self.hLayoutDisplayed.removeWidget(
            brewToRemove)  # remove widget from layout
        brewToRemove.setParent(None)  # remove parent so widget dissappears
        self.displayNo = self.displayNo - 1
        self.displayedBrewsH.remove(
            brewToRemove)  # remove brew from array of displayed brews
        i = 0
        # Loop to renumber the remaining displayed groupboxes using the array
        for i in range(len(self.displayedBrewsH)):
            self.displayedBrewsH[i].setTitle(str(i + 1))

        del self.activeColours[brewArrayPos]

    # Slot for removing group boxes of brew info in mash tab
    def removeBrewClickedMash(self, brewToRemove):

        # Obtain position in array of displayed brews of brew to remove
        brewArrayPos = self.displayedBrewsH.index(brewToRemove)
        # Use position to remove widget from layout
        self.tabMash.mashVLayout.takeAt(brewArrayPos)
        # Use position to remove parent
        self.displayedBrewsVMash[brewArrayPos].setParent(None)
        # Use position to delete from vertical array
        del self.displayedBrewsVMash[brewArrayPos]
        # Renumber groupboxes in vertical display
        for i in range(len(self.displayedBrewsVMash)):
            self.displayedBrewsVMash[i].setTitle(str(i + 1))

        # Remove curve from graph
        self.tabMash.graph.removeCurve(brewArrayPos)

    # Slot for removing group boxes of brew info in boil tab
    def removeBrewClickedBoil(self, brewToRemove):

        # Obtain position in array of displayed brews of brew to remove
        brewArrayPos = self.displayedBrewsH.index(brewToRemove)
        # Use position to remove widget from layout
        self.tabBoil.boilVLayout.takeAt(brewArrayPos)
        # Use position to remove parent
        self.displayedBrewsVBoil[brewArrayPos].setParent(None)
        # Use position to delete from vertical array
        del self.displayedBrewsVBoil[brewArrayPos]
        # Renumber groupboxes in vertical display
        for i in range(len(self.displayedBrewsVBoil)):
            self.displayedBrewsVBoil[i].setTitle(str(i + 1))

        self.tabBoil.graph.removeCurve(brewArrayPos)

    # Slot for removing group boxes of brew info in ferment tab
    def removeBrewClickedFerment(self, brewToRemove):

        # Obtain position in array of displayed brews of brew to remove
        brewArrayPos = self.displayedBrewsH.index(brewToRemove)
        # Use position to remove widget from layout
        self.tabFerment.fermentVLayout.takeAt(brewArrayPos)
        # Use position to remove parent
        self.displayedBrewsVFerment[brewArrayPos].setParent(None)
        # Use position to delete from vertical array
        del self.displayedBrewsVFerment[brewArrayPos]
        # Renumber groupboxes in vertical display
        for i in range(len(self.displayedBrewsVFerment)):
            self.displayedBrewsVFerment[i].setTitle(str(i + 1))

        self.tabFerment.tempGraph.removeCurve(brewArrayPos)
        self.tabFerment.gravGraph.removeCurve(brewArrayPos)

    # Slot for filtering by Batch IDdisplayed
    def filter_batchID(self):
        self.lineEdit_recipe.clear()
        self.proxyModel.setFilterRegExp(self.edit_batchID.text())
        self.proxyModel.setFilterKeyColumn(0)

    # Slot for filtering by Recipe
    def filter_recipe(self):
        self.edit_batchID.clear()
        self.proxyModel.setFilterRegExp(self.lineEdit_recipe.text())
        self.proxyModel.setFilterKeyColumn(1)

    # Slot for filtering by date
    def filter_date(self):
        self.lineEdit_recipe.clear()
        self.edit_batchID.clear()
        self.proxyModel.setFilterRegExp(
            self.dateEdit.date().toString("dd/MM/yy"))
        self.proxyModel.setFilterKeyColumn(2)

    # Slot for clearing all filters
    def clearFilters(self):
        self.dateEdit.setDate(self.maxDate)
        self.proxyModel.setFilterRegExp('')
        self.proxyModel.setFilterKeyColumn(0)
        self.proxyModel.setFilterKeyColumn(1)
        self.proxyModel.setFilterKeyColumn(2)
        self.lineEdit_recipe.clear()
        self.edit_batchID.clear()
class SetChartDetailPopup(QDialog):
    def __init__(self, table_id, *args, **kwargs):
        super(SetChartDetailPopup, self).__init__(*args, **kwargs)
        layout = QHBoxLayout(margin=2)
        # left_layout = QVBoxLayout()
        self.table_id = table_id
        self.table_data_frame = None  # 表格数据的pandas Data Frame对象
        # 图表参数设置的控件
        self.chart_parameter = QWidget(parent=self)
        parameter_layout = QVBoxLayout(margin=0)
        parameter_layout.addWidget(QLabel('参数设置', objectName='widgetTip'))
        # 图表名称
        chart_name_layout = QHBoxLayout()
        chart_name_layout.addWidget(QLabel('图表名称:', objectName='headTip'))
        self.chart_name = QLineEdit()
        chart_name_layout.addWidget(self.chart_name)
        parameter_layout.addLayout(chart_name_layout)
        # 图表类型
        chart_category_layout = QHBoxLayout()
        chart_category_layout.addWidget(QLabel('图表类型:', objectName='headTip'))
        self.chart_category_combo = QComboBox()
        self.chart_category_combo.addItems([u'折线图', u'柱形图'])
        chart_category_layout.addWidget(self.chart_category_combo)
        chart_category_layout.addStretch()
        parameter_layout.addLayout(chart_category_layout)
        # 选择X轴
        chart_xaxis_layout = QHBoxLayout()
        chart_xaxis_layout.addWidget(QLabel('X 轴列名:', objectName='headTip'))
        self.x_axis_combo = QComboBox(currentTextChanged=self.x_axis_changed)
        chart_xaxis_layout.addWidget(self.x_axis_combo)
        chart_xaxis_layout.addStretch()
        parameter_layout.addLayout(chart_xaxis_layout)
        # Y轴设置
        parameter_layout.addWidget(QLabel('Y 轴列名:', objectName='headTip'))
        yaxis_layout = QHBoxLayout()
        left_yaxis_layout = QVBoxLayout()
        self.column_header_list = QListWidget()
        self.column_header_list.setMaximumWidth(180)
        left_yaxis_layout.addWidget(self.column_header_list)
        yaxis_layout.addLayout(left_yaxis_layout)
        # 中间按钮
        middle_yasis_layout = QVBoxLayout()
        middle_yasis_layout.addWidget(
            QPushButton('左轴→', objectName='addAxis', clicked=self.add_y_left))
        middle_yasis_layout.addWidget(
            QPushButton('右轴→', objectName='addAxis', clicked=self.add_y_right))
        yaxis_layout.addLayout(middle_yasis_layout)
        # 右侧列头显示
        right_yaxis_layout = QVBoxLayout()
        self.right_top_list = QListWidget(
            doubleClicked=self.remove_toplist_item)
        self.right_top_list.setMaximumWidth(180)
        right_yaxis_layout.addWidget(self.right_top_list)
        self.right_bottom_list = QListWidget(
            doubleClicked=self.remove_bottomlist_item)
        self.right_bottom_list.setMaximumWidth(180)
        right_yaxis_layout.addWidget(self.right_bottom_list)
        yaxis_layout.addLayout(right_yaxis_layout)
        parameter_layout.addLayout(yaxis_layout)
        # 轴名称设置
        parameter_layout.addWidget(QLabel('轴名称设置:', objectName='headTip'),
                                   alignment=Qt.AlignLeft)
        # x轴
        bottom_xaxis_name_layout = QHBoxLayout()
        bottom_xaxis_name_layout.addWidget(QLabel('X 轴:'))
        self.bottom_x_label_edit = QLineEdit(placeholderText='请输入轴名称')
        bottom_xaxis_name_layout.addWidget(self.bottom_x_label_edit)
        parameter_layout.addLayout(bottom_xaxis_name_layout)
        # Y轴
        yaxis_name_layout = QHBoxLayout()
        yaxis_name_layout.addWidget(QLabel('左轴:'))
        self.left_y_label_edit = QLineEdit(placeholderText='请输入左轴名称')
        yaxis_name_layout.addWidget(self.left_y_label_edit)
        yaxis_name_layout.addWidget(QLabel('右轴:'))
        self.right_y_label_edit = QLineEdit(placeholderText='请输入右轴名称')
        yaxis_name_layout.addWidget(self.right_y_label_edit)
        parameter_layout.addLayout(yaxis_name_layout)
        # 数据范围
        parameter_layout.addWidget(QLabel('数据范围设置:', objectName='headTip'),
                                   alignment=Qt.AlignLeft)
        chart_scope_layout1 = QHBoxLayout()
        chart_scope_layout1.addWidget(QLabel('起始日期:'))
        self.scope_start_date = QDateEdit()
        self.scope_start_date.setCalendarPopup(True)
        self.scope_start_date.setEnabled(False)
        chart_scope_layout1.addWidget(self.scope_start_date)
        chart_scope_layout1.addWidget(QLabel('截止日期:'))
        self.scope_end_date = QDateEdit()
        self.scope_end_date.setCalendarPopup(True)
        self.scope_end_date.setEnabled(False)
        chart_scope_layout1.addWidget(self.scope_end_date)
        parameter_layout.addLayout(chart_scope_layout1)
        parameter_layout.addWidget(QPushButton(
            '画图预览', clicked=self.review_chart_clicked),
                                   alignment=Qt.AlignRight)
        self.chart_parameter.setMaximumWidth(350)
        self.chart_parameter.setLayout(parameter_layout)
        # 参数设置控件加入布局
        layout.addWidget(self.chart_parameter)
        # 预览控件
        self.review_widget = QWidget(parent=self)
        review_layout = QVBoxLayout(margin=0)
        review_layout.addWidget(QLabel('图表预览', objectName='widgetTip'))
        self.review_chart = QChartView()
        self.review_chart.setRenderHint(QPainter.Antialiasing)
        review_layout.addWidget(self.review_chart)
        # # 图例显示区
        # self.legend_view = QWidget(parent=self.review_widget)
        # legend_layout = QGridLayout()
        # self.legend_view.setLayout(legend_layout)
        # review_layout.addWidget(self.legend_view)
        # 确认设置
        commit_layout = QHBoxLayout()
        commit_layout.addStretch()
        self.current_start = QCheckBox('当前起始')
        commit_layout.addWidget(self.current_start)
        self.current_end = QCheckBox('当前截止')
        commit_layout.addWidget(self.current_end)
        commit_layout.addWidget(
            QPushButton('确认设置', clicked=self.commit_add_chart))
        review_layout.addLayout(commit_layout)
        # 表详情数据显示
        self.detail_trend_table = QTableWidget()
        self.detail_trend_table.setMaximumHeight(200)
        review_layout.addWidget(self.detail_trend_table)
        self.review_widget.setLayout(review_layout)
        layout.addWidget(self.review_widget)
        self.setLayout(layout)
        self.setMinimumWidth(950)
        self.setMaximumHeight(550)
        self.has_review_chart = False
        self.setStyleSheet("""
        #widgetTip{
            color: rgb(50,80,180);
            font-weight:bold
        }
        #headTip{
            font-weight:bold
        }
        #addAxis{
            max-width:40px
        }
        """)

    # x轴选择改变
    def x_axis_changed(self):
        self.column_header_list.clear()
        for header_index in range(
                self.detail_trend_table.horizontalHeader().count()):
            text = self.detail_trend_table.horizontalHeaderItem(
                header_index).text()
            if text == self.x_axis_combo.currentText():
                continue
            self.column_header_list.addItem(text)
        # 清空左轴和右轴的设置
        self.right_top_list.clear()
        self.right_bottom_list.clear()

    # 移除当前列表中的item
    def remove_toplist_item(self, index):
        row = self.right_top_list.currentRow()
        self.right_top_list.takeItem(row)

    def remove_bottomlist_item(self, index):
        row = self.right_bottom_list.currentRow()
        self.right_bottom_list.takeItem(row)

    # 加入左轴
    def add_y_left(self):
        text_in = list()
        for i in range(self.right_top_list.count()):
            text_in.append(self.right_top_list.item(i).text())
        item = self.column_header_list.currentItem()  # 获取item
        if item is not None:
            if item.text() not in text_in:
                self.right_top_list.addItem(item.text())

    # 加入右轴
    def add_y_right(self):
        text_in = list()
        for i in range(self.right_bottom_list.count()):
            text_in.append(self.right_bottom_list.item(i).text())
        item = self.column_header_list.currentItem()  # 获取item
        if item is not None:
            if item.text() not in text_in:
                self.right_bottom_list.addItem(item.text())

    # 预览数据
    def review_chart_clicked(self):
        try:
            chart_name = self.chart_name.text()
            chart_category = self.chart_category_combo.currentText()
            # 根据设置从表格中获取画图源数据
            x_axis = self.x_axis_combo.currentText()  # x轴
            left_y_axis = [
                self.right_top_list.item(i).text()
                for i in range(self.right_top_list.count())
            ]
            right_y_axis = [
                self.right_bottom_list.item(i).text()
                for i in range(self.right_bottom_list.count())
            ]
            # 根据表头将这些列名称换为索引
            x_axis_col = list()
            left_y_cols = list()
            right_y_cols = list()
            header_data = list()
            for header_index in range(
                    self.detail_trend_table.horizontalHeader().count()):
                text = self.detail_trend_table.horizontalHeaderItem(
                    header_index).text()
                header_data.append(text)
                if text == x_axis:
                    x_axis_col.append(header_index)
                for y_left in left_y_axis:
                    if y_left == text:
                        left_y_cols.append(header_index)
                for y_right in right_y_axis:
                    if y_right == text:
                        right_y_cols.append(header_index)
            # 判断是否选择了左轴
            if not left_y_cols:
                popup = InformationPopup(message='请至少选择一列左轴数据。', parent=self)
                if not popup.exec_():
                    popup.deleteLater()
                    del popup
                return
            # 根据设置画图
            start_date = self.scope_start_date.date().toString('yyyy-MM-dd')
            start_date = pd.to_datetime(start_date)
            end_date = self.scope_end_date.date().toString('yyyy-MM-dd')
            end_date = pd.to_datetime(end_date)
            df = self.table_data_frame.copy()
            final_df = df.loc[(df[0] >= start_date)
                              & (df[0] <= end_date)].copy()  # 根据时间范围取数
            # 根据类型进行画图
            if chart_category == u'折线图':  # 折线图
                chart = lines_stacked(name=chart_name,
                                      table_df=final_df,
                                      x_bottom_cols=x_axis_col,
                                      y_left_cols=left_y_cols,
                                      y_right_cols=right_y_cols,
                                      legend_labels=header_data,
                                      tick_count=12)
                # 设置图例
                # chart.legend().hide()
                # markers = chart.legend().markers()
                # print(markers)
                # row_index = 0
                # col_index = 0
                # for marker in chart.legend().markers():
                #     print(marker.series().name())
                #     # from PyQt5.QtChart import QLineSeries
                #     # QLineSeries.name()
                #     # 每条线设置一个label
                #     legend_label = QLabel(marker.series().name())
                #     self.legend_view.layout().addWidget(legend_label, row_index, col_index)
                #     col_index += 1
                #     if col_index >= 3:
                #         row_index += 1
                #         col_index = 0

            elif chart_category == u'柱形图':
                chart = bars_stacked(name=chart_name,
                                     table_df=final_df,
                                     x_bottom_cols=x_axis_col,
                                     y_left_cols=left_y_cols,
                                     y_right_cols=right_y_cols,
                                     legend_labels=header_data,
                                     tick_count=12)
            else:
                popup = InformationPopup(message='当前设置不适合作图或系统暂不支持作图。',
                                         parent=self)
                if not popup.exec_():
                    popup.deleteLater()
                    del popup
                return
            self.review_chart.setChart(chart)
            self.has_review_chart = True
        except Exception as e:
            popup = InformationPopup(message=str(e), parent=self)
            if not popup.exec_():
                popup.deleteLater()
                del popup

    # 确认添加本张图表
    def commit_add_chart(self):
        if not self.has_review_chart:
            info = InformationPopup(message='请先预览图表,再进行设置!', parent=self)
            if not info.exec_():
                info.deleteLater()
                del info
            return
        category_dict = {
            '折线图': 'line',
            '柱形图': 'bar',
        }
        chart_name = re.sub(r'\s+', '', self.chart_name.text())
        category = category_dict.get(self.chart_category_combo.currentText(),
                                     None)
        if not all([chart_name, category]):
            info = InformationPopup(message='请设置图表名称和图表类型!', parent=self)
            if not info.exec_():
                info.deleteLater()
                del info
            return
        # 根据设置从表格中获取数据把选择的列头变为索引
        x_axis = self.x_axis_combo.currentText()  # x轴
        left_y_axis = [
            self.right_top_list.item(i).text()
            for i in range(self.right_top_list.count())
        ]
        right_y_axis = [
            self.right_bottom_list.item(i).text()
            for i in range(self.right_bottom_list.count())
        ]
        # 根据表头将这些列名称换为索引
        x_axis_cols = list()
        left_y_cols = list()
        right_y_cols = list()
        for header_index in range(
                self.detail_trend_table.horizontalHeader().count()):
            text = self.detail_trend_table.horizontalHeaderItem(
                header_index).text()
            if text == x_axis:
                x_axis_cols.append(header_index)
            for y_left in left_y_axis:
                if y_left == text:
                    left_y_cols.append(header_index)
            for y_right in right_y_axis:
                if y_right == text:
                    right_y_cols.append(header_index)
        if not x_axis_cols:
            info = InformationPopup(message='请设置图表X轴!', parent=self)
            if not info.exec_():
                info.deleteLater()
                del info
            return
        if not left_y_cols:
            info = InformationPopup(message='至少左轴要有一列数据!', parent=self)
            if not info.exec_():
                info.deleteLater()
                del info
            return
        # 获取轴名称
        x_bottom_labels = re.split(r';', self.bottom_x_label_edit.text())
        y_left_labels = re.split(r';', self.left_y_label_edit.text())
        y_right_labels = re.split(r';', self.right_y_label_edit.text())
        chart_params = dict()
        chart_params['table_id'] = self.table_id
        chart_params['name'] = chart_name
        chart_params['category'] = category
        chart_params['x_bottom'] = x_axis_cols
        chart_params['x_bottom_label'] = x_bottom_labels
        chart_params['x_top'] = []
        chart_params['x_top_label'] = []
        chart_params['y_left'] = left_y_cols
        chart_params['y_left_label'] = y_left_labels
        chart_params['y_right'] = right_y_cols
        chart_params['y_right_label'] = y_right_labels
        chart_params['is_top'] = False
        if self.current_start.isChecked():
            # print('设置当前起始范围')
            chart_params['start'] = self.scope_start_date.date().toString(
                'yyyy-MM-dd')
        if self.current_end.isChecked():
            # print('设置当前截止')
            chart_params['end'] = self.scope_end_date.date().toString(
                'yyyy-MM-dd')
        # print(chart_params)
        # 上传数据
        try:
            r = requests.post(url=settings.SERVER_ADDR + 'trend/chart/?mc=' +
                              settings.app_dawn.value('machine'),
                              headers={
                                  'AUTHORIZATION':
                                  settings.app_dawn.value('AUTHORIZATION')
                              },
                              data=json.dumps(chart_params))
            response = json.loads(r.content.decode('utf-8'))
            if r.status_code != 201:
                raise ValueError(response['message'])
            message = response['message']
        except Exception as e:
            message = str(e)
        info = InformationPopup(message=message, parent=self)
        if not info.exec_():
            info.deleteLater()
            del info

    # 获取当前表的数据(预用来设置显示图的数据)
    def getCurrentTrendTable(self):
        try:
            r = requests.get(url=settings.SERVER_ADDR + 'trend/table/' +
                             str(self.table_id) + '/?look=1&mc=' +
                             settings.app_dawn.value('machine'))
            response = json.loads(r.content.decode('utf-8'))
            if r.status_code != 200:
                raise ValueError(response['message'])
        except Exception:
            pass
        else:
            column_headers = response['data']['header_data']
            column_headers.pop(0)
            self.x_axis_combo.addItems(column_headers)  # X轴选择
            for text in column_headers:
                if text in self.x_axis_combo.currentText():
                    continue
                self.column_header_list.addItem(text)  # 列头待选表
            # pandas处理数据
            self.table_data_frame = self.pd_handler_data(
                response['data']['table_data'])
            # 填充表格
            self.showTableData(column_headers, self.table_data_frame)

    # pandas 处理数据
    def pd_handler_data(self, table_data):
        # 转为DF
        table_df = pd.DataFrame(table_data)
        table_df.drop(columns=[0], inplace=True)  # 删除id列
        table_df.columns = [i for i in range(table_df.shape[1])]  # 重置列索引
        table_df[0] = pd.to_datetime(table_df[0])  # 第一列转为时间类型
        table_df.sort_values(by=0, inplace=True)  # 根据时间排序数据
        # 计算数据时间跨度大小显示在范围上
        min_x, max_x = table_df[0].min(), table_df[0].max(
        )  # 第一列时间数据(x轴)的最大值和最小值
        self.scope_start_date.setDateRange(QDate(min_x), QDate(max_x))
        self.scope_end_date.setDateRange(QDate(min_x), QDate(max_x))
        self.scope_start_date.setEnabled(True)
        self.scope_end_date.setEnabled(True)
        self.scope_end_date.setDate(self.scope_end_date.maximumDate())
        return table_df

    # 设置表格显示表数据内容
    def showTableData(self, headers, table_df):
        # 设置行列
        self.detail_trend_table.setRowCount(table_df.shape[0])
        col_count = len(headers)
        self.detail_trend_table.setColumnCount(col_count)
        self.detail_trend_table.setHorizontalHeaderLabels(headers)
        self.detail_trend_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)
        for row, row_content in enumerate(table_df.values.tolist()):
            for col, value in enumerate(row_content):
                if col == 0:  # 时间类
                    value = value.strftime('%Y-%m-%d')
                item = QTableWidgetItem(value)
                item.setTextAlignment(Qt.AlignCenter)
                self.detail_trend_table.setItem(row, col, item)
Example #8
0
class DateCreatorWindow(QDialog):
    """
    Dialog window for creation / editing date.
    """
    def __init__(self, parent: QWidget = None):
        super().__init__(parent)

        self._date = None
        self._date_delta = 7
        self._date_start_temp = QDate.currentDate()

        # window settings
        self.setWindowTitle(self.tr("Date creator"))

        # toggle and status
        self.check_box = QCheckBox(self.tr("Range date"))

        # date layout
        self.layout_date_edit = QFormLayout()

        # simple date layout
        self.label_simple_date = QLabel(self.tr("Date"))
        self.layout_date_edit.setWidget(0, QFormLayout.LabelRole,
                                        self.label_simple_date)
        self.date_edit_simple = QDateEdit()
        self.layout_date_edit.setWidget(0, QFormLayout.FieldRole,
                                        self.date_edit_simple)

        self.date_edit_simple.setCalendarPopup(True)
        self.date_edit_simple.setDisplayFormat("dd.MM.yyyy")
        self.date_edit_simple.setDate(QDate.currentDate())
        self.date_edit_simple.setDateRange(QDate.currentDate().addDays(-365),
                                           QDate.currentDate().addDays(365))

        # range date layout
        self.label_date_start = QLabel(self.tr("Start"))
        self.layout_date_edit.setWidget(1, QFormLayout.LabelRole,
                                        self.label_date_start)
        self.date_edit_start = QDateEdit()
        self.layout_date_edit.setWidget(1, QFormLayout.FieldRole,
                                        self.date_edit_start)

        self.label_date_end = QLabel(self.tr("End"))
        self.layout_date_edit.setWidget(2, QFormLayout.LabelRole,
                                        self.label_date_end)
        self.date_edit_end = QDateEdit()
        self.layout_date_edit.setWidget(2, QFormLayout.FieldRole,
                                        self.date_edit_end)

        self.label_date_frequency = QLabel(self.tr("Frequency"))
        self.layout_date_edit.setWidget(3, QFormLayout.LabelRole,
                                        self.label_date_frequency)
        self.combo_box_frequency = QComboBox()
        self.layout_date_edit.setWidget(3, QFormLayout.FieldRole,
                                        self.combo_box_frequency)

        self.date_edit_start.setCalendarPopup(True)
        self.date_edit_start.setDisplayFormat("dd.MM.yyyy")
        self.date_edit_start.setDate(QDate.currentDate())
        self.date_edit_start.setDateRange(QDate.currentDate().addDays(-365),
                                          QDate.currentDate().addDays(365))

        self.date_edit_end.setCalendarPopup(True)
        self.date_edit_end.setDisplayFormat("dd.MM.yyyy")
        self.date_edit_end.setDate(QDate.currentDate().addDays(
            self._date_delta))
        self.date_edit_end.setDateRange(
            QDate.currentDate().addDays(self._date_delta),
            QDate.currentDate().addDays(365))

        self.combo_box_frequency.addItem(str(FrequencyDate.Every),
                                         FrequencyDate.Every)
        self.combo_box_frequency.addItem(str(FrequencyDate.Throughout),
                                         FrequencyDate.Throughout)

        # navigate
        self.layout_navigate = QHBoxLayout()

        self.layout_navigate.addStretch(1)

        self.push_button_ok = QPushButton(self.tr("OK"))
        self.layout_navigate.addWidget(self.push_button_ok)

        self.push_button_apply = QPushButton(self.tr("Apply"))
        self.layout_navigate.addWidget(self.push_button_apply)

        self.push_button_cancel = QPushButton(self.tr("Cancel"))
        self.layout_navigate.addWidget(self.push_button_cancel)

        # layout setup
        self.layout_main = QVBoxLayout()
        self.layout_main.setAlignment(Qt.AlignCenter)

        self.layout_main.addWidget(self.check_box)
        self.layout_main.addLayout(self.layout_date_edit)
        self.layout_main.addStretch(1)
        self.layout_main.addLayout(self.layout_navigate)

        self.setLayout(self.layout_main)

        # connection
        self.check_box.clicked.connect(self.check_box_clicked)
        self.date_edit_start.dateChanged.connect(self.date_edit_start_change)
        self.date_edit_end.dateChanged.connect(self.date_range_validation)
        self.combo_box_frequency.currentIndexChanged.connect(
            self.combo_box_frequency_changed)
        self.push_button_ok.clicked.connect(self.push_button_ok_clicked)
        self.push_button_apply.clicked.connect(self.push_button_apply_clicked)
        self.push_button_cancel.clicked.connect(
            self.push_button_cancel_clicked)

        self.show_simple_date()

    def set_date(self, date_item) -> None:
        """
        Sets the date for editing.

        :param date_item: Set date
        """
        if isinstance(date_item, DateItem):
            self.show_simple_date()
            self.date_edit_simple.setDate(
                QDate.fromString(date_item.date, "yyyy.MM.dd"))
            self._date = date_item

        if isinstance(date_item, DateRange):
            self.check_box.setChecked(True)
            self.show_range_date()
            self.date_edit_start.setDate(
                QDate.fromString(date_item.date_from, "yyyy.MM.dd"))
            self.date_edit_end.setDate(
                QDate.fromString(date_item.date_to, "yyyy.MM.dd"))
            self.combo_box_frequency.setCurrentText(str(date_item.frequency))
            self._date = date_item

    def get_date(self) -> (DateItem, DateRange, None):
        """
        Returns the created date.
        """
        return self._date

    def show_simple_date(self) -> None:
        """
        Switches the window to simple date editing mode.
        """
        self.label_simple_date.setVisible(True)
        self.date_edit_simple.setVisible(True)

        self.label_date_start.setVisible(False)
        self.date_edit_start.setVisible(False)
        self.label_date_end.setVisible(False)
        self.date_edit_end.setVisible(False)
        self.label_date_frequency.setVisible(False)
        self.combo_box_frequency.setVisible(False)

    def show_range_date(self) -> None:
        """
        Switches the window to range date editing mode.
        """
        self.label_date_start.setVisible(True)
        self.date_edit_start.setVisible(True)
        self.label_date_end.setVisible(True)
        self.date_edit_end.setVisible(True)
        self.label_date_frequency.setVisible(True)
        self.combo_box_frequency.setVisible(True)

        self.label_simple_date.setVisible(False)
        self.date_edit_simple.setVisible(False)

    def date_edit_start_change(self, date: QDate) -> None:
        """
        Slot for changing the end of a range of dates.

        :param date: Start of the date range
        """
        end_date = self.date_edit_end.date().addDays(
            self._date_start_temp.daysTo(date))
        self.date_edit_end.setDateRange(date.addDays(self._date_delta),
                                        date.addDays(365))
        self.date_edit_end.setDate(end_date)
        self._date_start_temp = QDate(date)

    def combo_box_frequency_changed(self, index: int) -> None:
        """
        Slot for frequency combo box.

        :param index: Current index
        """
        if index == 0:
            self._date_delta = 7
        else:
            self._date_delta = 14

        self.date_edit_end.setDateRange(
            self.date_edit_start.date().addDays(self._date_delta),
            self.date_edit_start.date().addDays(365))
        self.date_range_validation()

    def date_range_validation(self) -> None:
        """
        Checks the correctness of the entered dates.
        """
        if self.date_edit_start.date().dayOfWeek() == self.date_edit_end.date(
        ).dayOfWeek():
            if self.date_edit_start.date().daysTo(
                    self.date_edit_end.date()) % self._date_delta == 0:
                msg = ""
            else:
                msg = self.tr("The number of days between "
                              "dates is not a multiple of {}").format(
                                  self._date_delta)
        else:
            msg = self.tr("Different days of the week at dates")

        if msg == "":
            self.push_button_ok.setEnabled(True)
            self.push_button_apply.setEnabled(True)
        else:
            self.push_button_ok.setEnabled(False)
            self.push_button_apply.setEnabled(False)

        self.date_edit_start.setToolTip(msg)
        self.date_edit_end.setToolTip(msg)

    def check_box_clicked(self, value: bool) -> None:
        """
        Slot for check box.

        :param value: Check box status
        """
        if value is False:
            # simple date
            self.show_simple_date()
        else:
            # range date
            self.show_range_date()

    def push_button_ok_clicked(self) -> None:
        """
        Slot for ok button.
        """
        if self.push_button_apply_clicked():
            self.close()

    def push_button_apply_clicked(self) -> bool:
        """
        Slot for apply button.
        """
        try:
            if self.check_box.isChecked() is False:
                # simple date
                self._date = DateItem(
                    self.date_edit_simple.date().toString("yyyy.MM.dd"))
            else:
                # range date
                self._date = DateRange(
                    self.date_edit_start.date().toString("yyyy.MM.dd"),
                    self.date_edit_end.date().toString("yyyy.MM.dd"),
                    self.combo_box_frequency.currentData(Qt.UserRole))
            return True
        except InvalidDatePair as pair_ex:
            QMessageBox.warning(self, self.tr("Date error"), str(pair_ex))

        except Exception as ex:
            QMessageBox.critical(self, self.tr("Unknown error"), str(ex))

        return False

    def push_button_cancel_clicked(self) -> None:
        """
        Slot for cancel button.
        """
        self._date = None
        self.close()
Example #9
0
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()

        self.createPreviewGroupBox()
        self.createGeneralOptionsGroupBox()
        self.createDatesGroupBox()
        self.createTextFormatsGroupBox()

        layout = QGridLayout()
        layout.addWidget(self.previewGroupBox, 0, 0)
        layout.addWidget(self.generalOptionsGroupBox, 0, 1)
        layout.addWidget(self.datesGroupBox, 1, 0)
        layout.addWidget(self.textFormatsGroupBox, 1, 1)
        layout.setSizeConstraint(QLayout.SetFixedSize)
        self.setLayout(layout)

        self.previewLayout.setRowMinimumHeight(0,
                self.calendar.sizeHint().height())
        self.previewLayout.setColumnMinimumWidth(0,
                self.calendar.sizeHint().width())

        self.setWindowTitle("Calendar Widget")

    def localeChanged(self, index):
        self.calendar.setLocale(self.localeCombo.itemData(index))

    def firstDayChanged(self, index):
        self.calendar.setFirstDayOfWeek(
                Qt.DayOfWeek(self.firstDayCombo.itemData(index)))

    def selectionModeChanged(self, index):
        self.calendar.setSelectionMode(
                QCalendarWidget.SelectionMode(
                        self.selectionModeCombo.itemData(index)))

    def horizontalHeaderChanged(self, index):
        self.calendar.setHorizontalHeaderFormat(
                QCalendarWidget.HorizontalHeaderFormat(
                        self.horizontalHeaderCombo.itemData(index)))

    def verticalHeaderChanged(self, index):
        self.calendar.setVerticalHeaderFormat(
                QCalendarWidget.VerticalHeaderFormat(
                        self.verticalHeaderCombo.itemData(index)))

    def selectedDateChanged(self):
        self.currentDateEdit.setDate(self.calendar.selectedDate())

    def minimumDateChanged(self, date):
        self.calendar.setMinimumDate(date)
        self.maximumDateEdit.setDate(self.calendar.maximumDate())

    def maximumDateChanged(self, date):
        self.calendar.setMaximumDate(date)
        self.minimumDateEdit.setDate(self.calendar.minimumDate())

    def weekdayFormatChanged(self):
        format = QTextCharFormat()
        format.setForeground(
                Qt.GlobalColor(
                        self.weekdayColorCombo.itemData(
                                self.weekdayColorCombo.currentIndex())))

        self.calendar.setWeekdayTextFormat(Qt.Monday, format)
        self.calendar.setWeekdayTextFormat(Qt.Tuesday, format)
        self.calendar.setWeekdayTextFormat(Qt.Wednesday, format)
        self.calendar.setWeekdayTextFormat(Qt.Thursday, format)
        self.calendar.setWeekdayTextFormat(Qt.Friday, format)

    def weekendFormatChanged(self):
        format = QTextCharFormat()
        format.setForeground(
                Qt.GlobalColor(
                        self.weekendColorCombo.itemData(
                                self.weekendColorCombo.currentIndex())))

        self.calendar.setWeekdayTextFormat(Qt.Saturday, format)
        self.calendar.setWeekdayTextFormat(Qt.Sunday, format)

    def reformatHeaders(self):
        text = self.headerTextFormatCombo.currentText()
        format = QTextCharFormat()

        if text == "Bold":
            format.setFontWeight(QFont.Bold)
        elif text == "Italic":
            format.setFontItalic(True)
        elif text == "Green":
            format.setForeground(Qt.green)

        self.calendar.setHeaderTextFormat(format)

    def reformatCalendarPage(self):
        if self.firstFridayCheckBox.isChecked():
            firstFriday = QDate(self.calendar.yearShown(),
                    self.calendar.monthShown(), 1)

            while firstFriday.dayOfWeek() != Qt.Friday:
                firstFriday = firstFriday.addDays(1)

            firstFridayFormat = QTextCharFormat()
            firstFridayFormat.setForeground(Qt.blue)

            self.calendar.setDateTextFormat(firstFriday, firstFridayFormat)

        # May 1st in Red takes precedence.
        if self.mayFirstCheckBox.isChecked():
            mayFirst = QDate(self.calendar.yearShown(), 5, 1)

            mayFirstFormat = QTextCharFormat()
            mayFirstFormat.setForeground(Qt.red)

            self.calendar.setDateTextFormat(mayFirst, mayFirstFormat)

    def createPreviewGroupBox(self):
        self.previewGroupBox = QGroupBox("Preview")

        self.calendar = QCalendarWidget()
        self.calendar.setMinimumDate(QDate(1900, 1, 1))
        self.calendar.setMaximumDate(QDate(3000, 1, 1))
        self.calendar.setGridVisible(True)
        self.calendar.currentPageChanged.connect(self.reformatCalendarPage)

        self.previewLayout = QGridLayout()
        self.previewLayout.addWidget(self.calendar, 0, 0, Qt.AlignCenter)
        self.previewGroupBox.setLayout(self.previewLayout)
 
    def createGeneralOptionsGroupBox(self):
        self.generalOptionsGroupBox = QGroupBox("General Options")

        self.localeCombo = QComboBox()

        curLocaleIndex = -1
        index = 0

        this_language = self.locale().nativeLanguageName()
        this_country = self.locale().nativeCountryName()

        for locale in QLocale.matchingLocales(QLocale.AnyLanguage, QLocale.AnyScript, QLocale.AnyCountry):
            language = locale.nativeLanguageName()
            country = locale.nativeCountryName()

            if language == this_language and country == this_country:
                curLocaleIndex = index

            self.localeCombo.addItem('%s/%s' % (language, country), locale)
            index += 1

        if curLocaleIndex != -1:
            self.localeCombo.setCurrentIndex(curLocaleIndex)

        self.localeLabel = QLabel("&Locale")
        self.localeLabel.setBuddy(self.localeCombo)

        self.firstDayCombo = QComboBox()
        self.firstDayCombo.addItem("Sunday", Qt.Sunday)
        self.firstDayCombo.addItem("Monday", Qt.Monday)
        self.firstDayCombo.addItem("Tuesday", Qt.Tuesday)
        self.firstDayCombo.addItem("Wednesday", Qt.Wednesday)
        self.firstDayCombo.addItem("Thursday", Qt.Thursday)
        self.firstDayCombo.addItem("Friday", Qt.Friday)
        self.firstDayCombo.addItem("Saturday", Qt.Saturday)

        self.firstDayLabel = QLabel("Wee&k starts on:")
        self.firstDayLabel.setBuddy(self.firstDayCombo)

        self.selectionModeCombo = QComboBox()
        self.selectionModeCombo.addItem("Single selection",
                QCalendarWidget.SingleSelection)
        self.selectionModeCombo.addItem("None",
                QCalendarWidget.NoSelection)
        self.selectionModeLabel = QLabel("&Selection mode:")
        self.selectionModeLabel.setBuddy(self.selectionModeCombo)

        self.gridCheckBox = QCheckBox("&Grid")
        self.gridCheckBox.setChecked(self.calendar.isGridVisible())

        self.navigationCheckBox = QCheckBox("&Navigation bar")
        self.navigationCheckBox.setChecked(True)

        self.horizontalHeaderCombo = QComboBox()
        self.horizontalHeaderCombo.addItem("Single letter day names",
                QCalendarWidget.SingleLetterDayNames)
        self.horizontalHeaderCombo.addItem("Short day names",
                QCalendarWidget.ShortDayNames)
        self.horizontalHeaderCombo.addItem("Long day names",
                QCalendarWidget.LongDayNames)
        self.horizontalHeaderCombo.addItem("None",
                QCalendarWidget.NoHorizontalHeader)
        self.horizontalHeaderCombo.setCurrentIndex(1)

        self.horizontalHeaderLabel = QLabel("&Horizontal header:")
        self.horizontalHeaderLabel.setBuddy(self.horizontalHeaderCombo)

        self.verticalHeaderCombo = QComboBox()
        self.verticalHeaderCombo.addItem("ISO week numbers",
                QCalendarWidget.ISOWeekNumbers)
        self.verticalHeaderCombo.addItem("None",
                QCalendarWidget.NoVerticalHeader)

        self.verticalHeaderLabel = QLabel("&Vertical header:")
        self.verticalHeaderLabel.setBuddy(self.verticalHeaderCombo)

        self.localeCombo.currentIndexChanged.connect(self.localeChanged)
        self.firstDayCombo.currentIndexChanged.connect(self.firstDayChanged)
        self.selectionModeCombo.currentIndexChanged.connect(
                self.selectionModeChanged)
        self.gridCheckBox.toggled.connect(self.calendar.setGridVisible)
        self.navigationCheckBox.toggled.connect(
                self.calendar.setNavigationBarVisible)
        self.horizontalHeaderCombo.currentIndexChanged.connect(
                self.horizontalHeaderChanged)
        self.verticalHeaderCombo.currentIndexChanged.connect(
                self.verticalHeaderChanged)

        checkBoxLayout = QHBoxLayout()
        checkBoxLayout.addWidget(self.gridCheckBox)
        checkBoxLayout.addStretch()
        checkBoxLayout.addWidget(self.navigationCheckBox)

        outerLayout = QGridLayout()
        outerLayout.addWidget(self.localeLabel, 0, 0)
        outerLayout.addWidget(self.localeCombo, 0, 1)
        outerLayout.addWidget(self.firstDayLabel, 1, 0)
        outerLayout.addWidget(self.firstDayCombo, 1, 1)
        outerLayout.addWidget(self.selectionModeLabel, 2, 0)
        outerLayout.addWidget(self.selectionModeCombo, 2, 1)
        outerLayout.addLayout(checkBoxLayout, 3, 0, 1, 2)
        outerLayout.addWidget(self.horizontalHeaderLabel, 4, 0)
        outerLayout.addWidget(self.horizontalHeaderCombo, 4, 1)
        outerLayout.addWidget(self.verticalHeaderLabel, 5, 0)
        outerLayout.addWidget(self.verticalHeaderCombo, 5, 1)
        self.generalOptionsGroupBox.setLayout(outerLayout)

        self.firstDayChanged(self.firstDayCombo.currentIndex())
        self.selectionModeChanged(self.selectionModeCombo.currentIndex())
        self.horizontalHeaderChanged(self.horizontalHeaderCombo.currentIndex())
        self.verticalHeaderChanged(self.verticalHeaderCombo.currentIndex())
 
    def createDatesGroupBox(self):
        self.datesGroupBox = QGroupBox(self.tr("Dates"))

        self.minimumDateEdit = QDateEdit()
        self.minimumDateEdit.setDisplayFormat('MMM d yyyy')
        self.minimumDateEdit.setDateRange(self.calendar.minimumDate(),
                                          self.calendar.maximumDate())
        self.minimumDateEdit.setDate(self.calendar.minimumDate())

        self.minimumDateLabel = QLabel("&Minimum Date:")
        self.minimumDateLabel.setBuddy(self.minimumDateEdit)

        self.currentDateEdit = QDateEdit()
        self.currentDateEdit.setDisplayFormat('MMM d yyyy')
        self.currentDateEdit.setDate(self.calendar.selectedDate())
        self.currentDateEdit.setDateRange(self.calendar.minimumDate(),
                self.calendar.maximumDate())

        self.currentDateLabel = QLabel("&Current Date:")
        self.currentDateLabel.setBuddy(self.currentDateEdit)

        self.maximumDateEdit = QDateEdit()
        self.maximumDateEdit.setDisplayFormat('MMM d yyyy')
        self.maximumDateEdit.setDateRange(self.calendar.minimumDate(),
                self.calendar.maximumDate())
        self.maximumDateEdit.setDate(self.calendar.maximumDate())

        self.maximumDateLabel = QLabel("Ma&ximum Date:")
        self.maximumDateLabel.setBuddy(self.maximumDateEdit)

        self.currentDateEdit.dateChanged.connect(self.calendar.setSelectedDate)
        self.calendar.selectionChanged.connect(self.selectedDateChanged)
        self.minimumDateEdit.dateChanged.connect(self.minimumDateChanged)
        self.maximumDateEdit.dateChanged.connect(self.maximumDateChanged)
 
        dateBoxLayout = QGridLayout()
        dateBoxLayout.addWidget(self.currentDateLabel, 1, 0)
        dateBoxLayout.addWidget(self.currentDateEdit, 1, 1)
        dateBoxLayout.addWidget(self.minimumDateLabel, 0, 0)
        dateBoxLayout.addWidget(self.minimumDateEdit, 0, 1)
        dateBoxLayout.addWidget(self.maximumDateLabel, 2, 0)
        dateBoxLayout.addWidget(self.maximumDateEdit, 2, 1)
        dateBoxLayout.setRowStretch(3, 1)

        self.datesGroupBox.setLayout(dateBoxLayout)

    def createTextFormatsGroupBox(self):
        self.textFormatsGroupBox = QGroupBox("Text Formats")

        self.weekdayColorCombo = self.createColorComboBox()
        self.weekdayColorCombo.setCurrentIndex(
                self.weekdayColorCombo.findText("Black"))

        self.weekdayColorLabel = QLabel("&Weekday color:")
        self.weekdayColorLabel.setBuddy(self.weekdayColorCombo)

        self.weekendColorCombo = self.createColorComboBox()
        self.weekendColorCombo.setCurrentIndex(
                self.weekendColorCombo.findText("Red"))

        self.weekendColorLabel = QLabel("Week&end color:")
        self.weekendColorLabel.setBuddy(self.weekendColorCombo)

        self.headerTextFormatCombo = QComboBox()
        self.headerTextFormatCombo.addItem("Bold")
        self.headerTextFormatCombo.addItem("Italic")
        self.headerTextFormatCombo.addItem("Plain")

        self.headerTextFormatLabel = QLabel("&Header text:")
        self.headerTextFormatLabel.setBuddy(self.headerTextFormatCombo)

        self.firstFridayCheckBox = QCheckBox("&First Friday in blue")

        self.mayFirstCheckBox = QCheckBox("May &1 in red")

        self.weekdayColorCombo.currentIndexChanged.connect(
                self.weekdayFormatChanged)
        self.weekendColorCombo.currentIndexChanged.connect(
                self.weekendFormatChanged)
        self.headerTextFormatCombo.currentIndexChanged.connect(
                self.reformatHeaders)
        self.firstFridayCheckBox.toggled.connect(self.reformatCalendarPage)
        self.mayFirstCheckBox.toggled.connect(self.reformatCalendarPage)

        checkBoxLayout = QHBoxLayout()
        checkBoxLayout.addWidget(self.firstFridayCheckBox)
        checkBoxLayout.addStretch()
        checkBoxLayout.addWidget(self.mayFirstCheckBox)

        outerLayout = QGridLayout()
        outerLayout.addWidget(self.weekdayColorLabel, 0, 0)
        outerLayout.addWidget(self.weekdayColorCombo, 0, 1)
        outerLayout.addWidget(self.weekendColorLabel, 1, 0)
        outerLayout.addWidget(self.weekendColorCombo, 1, 1)
        outerLayout.addWidget(self.headerTextFormatLabel, 2, 0)
        outerLayout.addWidget(self.headerTextFormatCombo, 2, 1)
        outerLayout.addLayout(checkBoxLayout, 3, 0, 1, 2)
        self.textFormatsGroupBox.setLayout(outerLayout)

        self.weekdayFormatChanged()
        self.weekendFormatChanged()

        self.reformatHeaders()
        self.reformatCalendarPage()
 
    def createColorComboBox(self):
        comboBox = QComboBox()
        comboBox.addItem("Red", Qt.red)
        comboBox.addItem("Blue", Qt.blue)
        comboBox.addItem("Black", Qt.black)
        comboBox.addItem("Magenta", Qt.magenta)

        return comboBox
Example #10
0
class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.setWindowTitle("Query Cocorahs")
        self.initUI()


    def initUI(self):
        self.createPreviewGroupBox()
        self.createDatesGroupBox()
        self.infoPanel()

        layout = QGridLayout()
        # layout.addWidget(self.previewGroupBox, 0, 0)
        layout.addWidget(self.datesGroupBox, 0, 1)
        layout.addWidget(self.infoPanelBox, 0, 2, 0, 1)
        layout.setSizeConstraint(QLayout.SetFixedSize)
        self.setLayout(layout)
        self.previewLayout.setRowMinimumHeight(0,
                self.calendar.sizeHint().height())
        self.previewLayout.setColumnMinimumWidth(0,
                self.calendar.sizeHint().width())


    def createPreviewGroupBox(self):
        self.previewGroupBox = QGroupBox("Calendar")
        self.calendar = QCalendarWidget()
        self.calendar.setMaximumDate(QDate(3000, 1, 1))
        self.calendar.setGridVisible(True)
        self.previewLayout = QGridLayout()
        self.previewLayout.addWidget(self.calendar, 0, 0)
        self.previewGroupBox.setLayout(self.previewLayout)


    def createDatesGroupBox(self):
        self.datesGroupBox = QGroupBox(self.tr("Selections"))

        # QUERY
        self.queryButton = QPushButton("Query Cocorahs Database")
        self.queryButton.clicked.connect(self.query_on_click)

        # START DATES
        self.currentDateEdit = QDateEdit()
        self.currentDateEdit.setDisplayFormat('dd MMM yyyy')
        self.currentDateEdit.setDate(self.calendar.selectedDate())
        self.currentDateEdit.setDateRange(self.calendar.minimumDate(),
                self.calendar.maximumDate())
        self.currentDateLabel = QLabel("&Date:")
        self.currentDateLabel.setBuddy(self.currentDateEdit)

        # END DATES
        self.maximumDateEdit = QDateEdit()
        self.maximumDateEdit.setDisplayFormat('dd MMM yyyy')
        self.maximumDateEdit.setDate(self.calendar.selectedDate())
        self.maximumDateEdit.setDateRange(self.calendar.minimumDate(),
                self.calendar.maximumDate())
        self.maximumDateLabel = QLabel("&End Date:")
        self.maximumDateLabel.setBuddy(self.maximumDateEdit)

        # LONGITUDE
        self.textboxLong = QLineEdit(self)
        self.textboxLongLabel = QLabel("Target Longitude:")

        # LATITUDE
        self.textboxLat = QLineEdit(self)
        self.textboxLatLabel = QLabel("Target Latitude:")

        # STATES
        self.textboxStates = QLineEdit(self)
        self.textboxStatesLabel = QLabel("State(s): e.g., 'CO,NE,WY'")

        dateBoxLayout = QGridLayout()
        dateBoxLayout.addWidget(self.currentDateLabel, 1, 0)
        dateBoxLayout.addWidget(self.currentDateEdit, 1, 1, 1, 2)
        # dateBoxLayout.addWidget(self.maximumDateLabel, 2, 0)
        # dateBoxLayout.addWidget(self.maximumDateEdit, 2, 1, 1, 2)
        dateBoxLayout.addWidget(self.textboxLatLabel, 3, 0)
        dateBoxLayout.addWidget(self.textboxLat, 3, 1, 1, 2)
        dateBoxLayout.addWidget(self.textboxLongLabel, 4, 0)
        dateBoxLayout.addWidget(self.textboxLong, 4, 1, 1, 2)
        dateBoxLayout.addWidget(self.textboxStatesLabel, 5, 0)
        dateBoxLayout.addWidget(self.textboxStates, 5, 1, 1, 2)
        dateBoxLayout.addWidget(self.queryButton, 6, 0,1,3)
        dateBoxLayout.setRowStretch(5, 1)
        self.datesGroupBox.setLayout(dateBoxLayout)


    def infoPanel(self):
        self.infoPanelBox = QGroupBox(self.tr("Info Console"))
        self.infoConsole = QTextEdit(self)
        infoPanelBoxLayout = QGridLayout()
        infoPanelBoxLayout.addWidget(self.infoConsole, 0, 0, 1, 1)
        self.infoPanelBox.setLayout(infoPanelBoxLayout)

    def query_on_click(self):
        long = self.textboxLong.text()
        lat = self.textboxLat.text()
        startDate = self.currentDateEdit.date()
        endDate = self.maximumDateEdit.date()
        states = self.textboxStates.text()
        date_range = list(range(startDate.month(), endDate.month() + 1))
        dateString = startDate.toString('MM/dd/yyyy')
        query(long=long, lat=lat, dateString=dateString, states=states)
Example #11
0
class CalendarGUI(QWidget):
    def __init__(self):
        super().__init__()
        self.initializeUI()

    def initializeUI(self):
        """
        Initialize the window and display its contents to the screen. 
        """
        self.setMinimumSize(500, 400)
        self.setWindowTitle('12.4 – Calendar GUI')

        self.createCalendar()

        self.show()

    def createCalendar(self):
        """
        Set up calendar, others widgets and layouts for main window. 
        """
        self.calendar = QCalendarWidget()
        self.calendar.setGridVisible(True)
        self.calendar.setMinimumDate(QDate(1900, 1, 1))
        self.calendar.setMaximumDate(QDate(2200, 1, 1))

        # Connect to newDateSelection slot when currently selected date is changed
        self.calendar.selectionChanged.connect(self.newDateSelection)

        current = QDate.currentDate().toString(Qt.DefaultLocaleLongDate)
        self.current_label = QLabel(current)
        self.current_label.setObjectName("DateSelected")

        # Create current, minimum and maximum QDateEdit widgets
        min_date_label = QLabel("Minimum Date:")
        self.min_date_edit = QDateEdit()
        self.min_date_edit.setDisplayFormat("MMM d yyyy")
        self.min_date_edit.setDateRange(self.calendar.minimumDate(),
                                        self.calendar.maximumDate())
        self.min_date_edit.setDate(self.calendar.minimumDate())
        self.min_date_edit.dateChanged.connect(self.minDatedChanged)

        current_date_label = QLabel("Current Date:")
        self.current_date_edit = QDateEdit()
        self.current_date_edit.setDisplayFormat("MMM d yyyy")
        self.current_date_edit.setDate(self.calendar.selectedDate())
        self.current_date_edit.setDateRange(self.calendar.minimumDate(),
                                            self.calendar.maximumDate())
        self.current_date_edit.dateChanged.connect(self.selectionDateChanged)

        max_date_label = QLabel("Maximum Date:")
        self.max_date_edit = QDateEdit()
        self.max_date_edit.setDisplayFormat("MMM d yyyy")
        self.max_date_edit.setDateRange(self.calendar.minimumDate(),
                                        self.calendar.maximumDate())
        self.max_date_edit.setDate(self.calendar.maximumDate())
        self.max_date_edit.dateChanged.connect(self.maxDatedChanged)

        # Add widgets to group box and add to grid layout
        dates_gb = QGroupBox("Set Dates")
        dates_grid = QGridLayout()
        dates_grid.addWidget(self.current_label, 0, 0, 1, 2, Qt.AlignAbsolute)
        dates_grid.addWidget(min_date_label, 1, 0)
        dates_grid.addWidget(self.min_date_edit, 1, 1)
        dates_grid.addWidget(current_date_label, 2, 0)
        dates_grid.addWidget(self.current_date_edit, 2, 1)
        dates_grid.addWidget(max_date_label, 3, 0)
        dates_grid.addWidget(self.max_date_edit, 3, 1)
        dates_gb.setLayout(dates_grid)

        # Create and set main window's layout
        main_h_box = QHBoxLayout()
        main_h_box.addWidget(self.calendar)
        main_h_box.addWidget(dates_gb)

        self.setLayout(main_h_box)

    def selectionDateChanged(self, date):
        """
        Update the current_date_edit when the calendar's selected date changes. 
        """
        self.calendar.setSelectedDate(date)

    def minDatedChanged(self, date):
        """
        Update the calendar's minimum date.
        Update max_date_edit to avoid conflicts with maximum and minimum dates.
        """
        self.calendar.setMinimumDate(date)
        self.max_date_edit.setDate(self.calendar.maximumDate())

    def maxDatedChanged(self, date):
        """
        Update the calendar's maximum date.
        Update min_date_edit to avoid conflicts with minimum and maximum dates. 
        """
        self.calendar.setMaximumDate(date)
        self.min_date_edit.setDate(self.calendar.minimumDate())

    def newDateSelection(self):
        """
        Update date in current_label and current_date_edit widgets
        when user selects a new date.
        """
        date = self.calendar.selectedDate().toString(Qt.DefaultLocaleLongDate)
        self.current_date_edit.setDate(self.calendar.selectedDate())
        self.current_label.setText(date)
Example #12
0
class Calendar(QWidget):

    key = 'calendar'
    showLayout = pyqtSignal(str, str)

    def __init__(self, parent=None):
        super(Calendar, self).__init__(parent)
        self.setWindowIcon(IconPth(32, 'Calendar'))

        self.layout = QGridLayout()
        self.buildUI()
        self.setLayout(self.layout)

    def buildUI(self):

        self.createPreviewGroupBox()
        self.createGeneralOptionsGroupBox()
        self.createDatesGroupBox()
        self.createTextFormatsGroupBox()

        self.layout.addWidget(self.previewGroupBox, 0, 0)
        self.layout.addWidget(self.generalOptionsGroupBox, 0, 1)
        self.layout.addWidget(self.datesGroupBox, 1, 0)
        self.layout.addWidget(self.textFormatsGroupBox, 1, 1)

        self.applySetting()

    def localeChanged(self, index):
        self.calendar.setLocale(self.localeCombo.itemData(index))

    def firstDayChanged(self, index):
        self.calendar.setFirstDayOfWeek(
            Qt.DayOfWeek(self.firstDayCombo.itemData(index)))

    def selectionModeChanged(self, index):
        self.calendar.setSelectionMode(
            QCalendarWidget.SelectionMode(
                self.selectionModeCombo.itemData(index)))

    def horizontalHeaderChanged(self, index):
        self.calendar.setHorizontalHeaderFormat(
            QCalendarWidget.HorizontalHeaderFormat(
                self.horizontalHeaderCombo.itemData(index)))

    def verticalHeaderChanged(self, index):
        self.calendar.setVerticalHeaderFormat(
            QCalendarWidget.VerticalHeaderFormat(
                self.verticalHeaderCombo.itemData(index)))

    def selectedDateChanged(self):
        self.currentDateEdit.setDate(self.calendar.selectedDate())

    def minimumDateChanged(self, date):
        self.calendar.setMinimumDate(date)
        self.maximumDateEdit.setDate(self.calendar.maximumDate())

    def maximumDateChanged(self, date):
        self.calendar.setMaximumDate(date)
        self.minimumDateEdit.setDate(self.calendar.minimumDate())

    def weekdayFormatChanged(self):
        format = QTextCharFormat()
        format.setForeground(
            Qt.GlobalColor(
                self.weekdayColorCombo.itemData(
                    self.weekdayColorCombo.currentIndex())))

        self.calendar.setWeekdayTextFormat(Qt.Monday, format)
        self.calendar.setWeekdayTextFormat(Qt.Tuesday, format)
        self.calendar.setWeekdayTextFormat(Qt.Wednesday, format)
        self.calendar.setWeekdayTextFormat(Qt.Thursday, format)
        self.calendar.setWeekdayTextFormat(Qt.Friday, format)

    def weekendFormatChanged(self):
        format = QTextCharFormat()
        format.setForeground(
            Qt.GlobalColor(
                self.weekendColorCombo.itemData(
                    self.weekendColorCombo.currentIndex())))

        self.calendar.setWeekdayTextFormat(Qt.Saturday, format)
        self.calendar.setWeekdayTextFormat(Qt.Sunday, format)

    def reformatHeaders(self):
        text = self.headerTextFormatCombo.currentText()
        format = QTextCharFormat()

        if text == "Bold":
            format.setFontWeight(QFont.Bold)
        elif text == "Italic":
            format.setFontItalic(True)
        elif text == "Green":
            format.setForeground(Qt.green)

        self.calendar.setHeaderTextFormat(format)

    def reformatCalendarPage(self):
        if self.firstFridayCheckBox.isChecked():
            firstFriday = QDate(self.calendar.yearShown(),
                                self.calendar.monthShown(), 1)

            while firstFriday.dayOfWeek() != Qt.Friday:
                firstFriday = firstFriday.addDays(1)

            firstFridayFormat = QTextCharFormat()
            firstFridayFormat.setForeground(Qt.blue)

            self.calendar.setDateTextFormat(firstFriday, firstFridayFormat)

        # May 1st in Red takes precedence.
        if self.mayFirstCheckBox.isChecked():
            mayFirst = QDate(self.calendar.yearShown(), 5, 1)

            mayFirstFormat = QTextCharFormat()
            mayFirstFormat.setForeground(Qt.red)

            self.calendar.setDateTextFormat(mayFirst, mayFirstFormat)

    def createPreviewGroupBox(self):
        self.previewGroupBox = QGroupBox("Preview")

        self.calendar = QCalendarWidget()
        self.calendar.setMinimumDate(QDate(1900, 1, 1))
        self.calendar.setMaximumDate(QDate(3000, 1, 1))
        self.calendar.setGridVisible(True)
        self.calendar.currentPageChanged.connect(self.reformatCalendarPage)

        self.previewLayout = QGridLayout()
        self.previewLayout.addWidget(self.calendar, 0, 0, Qt.AlignCenter)
        self.previewGroupBox.setLayout(self.previewLayout)

    def createGeneralOptionsGroupBox(self):
        self.generalOptionsGroupBox = QGroupBox("General Options")
        self.localeCombo = QComboBox()

        curLocaleIndex = -1
        lang_country = {}
        for lid in range(QLocale.C, QLocale.LastLanguage + 1):
            lang = (QLocale(lid).nativeLanguageName())
            country = u' '.join(
                QLocale(lid).nativeCountryName()).encode('utf-8').strip()
            lang_country[country] = [lang, lid]
            lid += 1

        countries = sorted(list(set([c for c in lang_country])))
        countries.remove(countries[0])
        for country in countries:
            lang = lang_country[country][0]
            label = "%s - %s" % (
                (u' '.join(lang).encode('Utf-8').strip()), country)
            locale = QLocale(lang_country[country][1])

            if self.locale().language() == lang and self.locale().country(
            ) == country:
                curLocaleIndex = lang_country[country][1]

            self.localeCombo.addItem(label, locale)

        if curLocaleIndex != -1:
            self.localeCombo.setCurrentIndex(curLocaleIndex)

        self.localeLabel = QLabel("&Locale")
        self.localeLabel.setBuddy(self.localeCombo)

        self.firstDayCombo = QComboBox()
        self.firstDayCombo.addItem("Sunday", Qt.Sunday)
        self.firstDayCombo.addItem("Monday", Qt.Monday)
        self.firstDayCombo.addItem("Tuesday", Qt.Tuesday)
        self.firstDayCombo.addItem("Wednesday", Qt.Wednesday)
        self.firstDayCombo.addItem("Thursday", Qt.Thursday)
        self.firstDayCombo.addItem("Friday", Qt.Friday)
        self.firstDayCombo.addItem("Saturday", Qt.Saturday)

        self.firstDayLabel = QLabel("Wee&k starts on:")
        self.firstDayLabel.setBuddy(self.firstDayCombo)

        self.selectionModeCombo = QComboBox()
        self.selectionModeCombo.addItem("Single selection",
                                        QCalendarWidget.SingleSelection)
        self.selectionModeCombo.addItem("None", QCalendarWidget.NoSelection)
        self.selectionModeLabel = QLabel("&Selection fm:")
        self.selectionModeLabel.setBuddy(self.selectionModeCombo)

        self.gridCheckBox = QCheckBox("&Grid")
        self.gridCheckBox.setChecked(self.calendar.isGridVisible())

        self.navigationCheckBox = QCheckBox("&Navigation bar")
        self.navigationCheckBox.setChecked(True)

        self.horizontalHeaderCombo = QComboBox()
        self.horizontalHeaderCombo.addItem(
            "Single letter day names", QCalendarWidget.SingleLetterDayNames)
        self.horizontalHeaderCombo.addItem("Short day names",
                                           QCalendarWidget.ShortDayNames)
        self.horizontalHeaderCombo.addItem("Long day names",
                                           QCalendarWidget.LongDayNames)
        self.horizontalHeaderCombo.addItem("None",
                                           QCalendarWidget.NoHorizontalHeader)
        self.horizontalHeaderCombo.setCurrentIndex(1)

        self.horizontalHeaderLabel = QLabel("&Horizontal header:")
        self.horizontalHeaderLabel.setBuddy(self.horizontalHeaderCombo)

        self.verticalHeaderCombo = QComboBox()
        self.verticalHeaderCombo.addItem("ISO week numbers",
                                         QCalendarWidget.ISOWeekNumbers)
        self.verticalHeaderCombo.addItem("None",
                                         QCalendarWidget.NoVerticalHeader)

        self.verticalHeaderLabel = QLabel("&Vertical header:")
        self.verticalHeaderLabel.setBuddy(self.verticalHeaderCombo)

        self.localeCombo.currentIndexChanged.connect(self.localeChanged)
        self.firstDayCombo.currentIndexChanged.connect(self.firstDayChanged)
        self.selectionModeCombo.currentIndexChanged.connect(
            self.selectionModeChanged)
        self.gridCheckBox.toggled.connect(self.calendar.setGridVisible)
        self.navigationCheckBox.toggled.connect(
            self.calendar.setNavigationBarVisible)
        self.horizontalHeaderCombo.currentIndexChanged.connect(
            self.horizontalHeaderChanged)
        self.verticalHeaderCombo.currentIndexChanged.connect(
            self.verticalHeaderChanged)

        checkBoxLayout = QHBoxLayout()
        checkBoxLayout.addWidget(self.gridCheckBox)
        checkBoxLayout.addStretch()
        checkBoxLayout.addWidget(self.navigationCheckBox)

        outerLayout = QGridLayout()
        outerLayout.addWidget(self.localeLabel, 0, 0, 1, 1)
        outerLayout.addWidget(self.localeCombo, 0, 1, 1, 1)
        outerLayout.addWidget(self.firstDayLabel, 1, 0, 1, 1)
        outerLayout.addWidget(self.firstDayCombo, 1, 1, 1, 1)
        outerLayout.addWidget(self.selectionModeLabel, 2, 0, 1, 1)
        outerLayout.addWidget(self.selectionModeCombo, 2, 1, 1, 1)
        outerLayout.addLayout(checkBoxLayout, 3, 0, 1, 2)
        outerLayout.addWidget(self.horizontalHeaderLabel, 5, 0, 1, 1)
        outerLayout.addWidget(self.horizontalHeaderCombo, 5, 1, 1, 1)
        outerLayout.addWidget(self.verticalHeaderLabel, 6, 0, 1, 1)
        outerLayout.addWidget(self.verticalHeaderCombo, 6, 1, 1, 1)
        self.generalOptionsGroupBox.setLayout(outerLayout)

        self.firstDayChanged(self.firstDayCombo.currentIndex())
        self.selectionModeChanged(self.selectionModeCombo.currentIndex())
        self.horizontalHeaderChanged(self.horizontalHeaderCombo.currentIndex())
        self.verticalHeaderChanged(self.verticalHeaderCombo.currentIndex())

    def createDatesGroupBox(self):
        self.datesGroupBox = QGroupBox(self.tr("Dates"))

        self.minimumDateEdit = QDateEdit()
        self.minimumDateEdit.setDisplayFormat('MMM d yyyy')
        self.minimumDateEdit.setDateRange(self.calendar.minimumDate(),
                                          self.calendar.maximumDate())
        self.minimumDateEdit.setDate(self.calendar.minimumDate())

        self.minimumDateLabel = QLabel("&Minimum Date:")
        self.minimumDateLabel.setBuddy(self.minimumDateEdit)

        self.currentDateEdit = QDateEdit()
        self.currentDateEdit.setDisplayFormat('MMM d yyyy')
        self.currentDateEdit.setDate(self.calendar.selectedDate())
        self.currentDateEdit.setDateRange(self.calendar.minimumDate(),
                                          self.calendar.maximumDate())

        self.currentDateLabel = QLabel("&Current Date:")
        self.currentDateLabel.setBuddy(self.currentDateEdit)

        self.maximumDateEdit = QDateEdit()
        self.maximumDateEdit.setDisplayFormat('MMM d yyyy')
        self.maximumDateEdit.setDateRange(self.calendar.minimumDate(),
                                          self.calendar.maximumDate())
        self.maximumDateEdit.setDate(self.calendar.maximumDate())

        self.maximumDateLabel = QLabel("Ma&ximum Date:")
        self.maximumDateLabel.setBuddy(self.maximumDateEdit)

        self.currentDateEdit.dateChanged.connect(self.calendar.setSelectedDate)
        self.calendar.selectionChanged.connect(self.selectedDateChanged)
        self.minimumDateEdit.dateChanged.connect(self.minimumDateChanged)
        self.maximumDateEdit.dateChanged.connect(self.maximumDateChanged)

        dateBoxLayout = QGridLayout()
        dateBoxLayout.addWidget(self.currentDateLabel, 1, 0)
        dateBoxLayout.addWidget(self.currentDateEdit, 1, 1)
        dateBoxLayout.addWidget(self.minimumDateLabel, 0, 0)
        dateBoxLayout.addWidget(self.minimumDateEdit, 0, 1)
        dateBoxLayout.addWidget(self.maximumDateLabel, 2, 0)
        dateBoxLayout.addWidget(self.maximumDateEdit, 2, 1)
        dateBoxLayout.setRowStretch(3, 1)

        self.datesGroupBox.setLayout(dateBoxLayout)

    def createTextFormatsGroupBox(self):
        self.textFormatsGroupBox = QGroupBox("Text Formats")

        self.weekdayColorCombo = self.createColorComboBox()
        self.weekdayColorCombo.setCurrentIndex(
            self.weekdayColorCombo.findText("Black"))

        self.weekdayColorLabel = QLabel("&Weekday color:")
        self.weekdayColorLabel.setBuddy(self.weekdayColorCombo)

        self.weekendColorCombo = self.createColorComboBox()
        self.weekendColorCombo.setCurrentIndex(
            self.weekendColorCombo.findText("Red"))

        self.weekendColorLabel = QLabel("Week&end color:")
        self.weekendColorLabel.setBuddy(self.weekendColorCombo)

        self.headerTextFormatCombo = QComboBox()
        self.headerTextFormatCombo.addItem("Bold")
        self.headerTextFormatCombo.addItem("Italic")
        self.headerTextFormatCombo.addItem("Plain")

        self.headerTextFormatLabel = QLabel("&Header text:")
        self.headerTextFormatLabel.setBuddy(self.headerTextFormatCombo)

        self.firstFridayCheckBox = QCheckBox("&First Friday in blue")

        self.mayFirstCheckBox = QCheckBox("May &1 in red")

        self.weekdayColorCombo.currentIndexChanged.connect(
            self.weekdayFormatChanged)
        self.weekendColorCombo.currentIndexChanged.connect(
            self.weekendFormatChanged)
        self.headerTextFormatCombo.currentIndexChanged.connect(
            self.reformatHeaders)
        self.firstFridayCheckBox.toggled.connect(self.reformatCalendarPage)
        self.mayFirstCheckBox.toggled.connect(self.reformatCalendarPage)

        checkBoxLayout = QHBoxLayout()
        checkBoxLayout.addWidget(self.firstFridayCheckBox)
        checkBoxLayout.addStretch()
        checkBoxLayout.addWidget(self.mayFirstCheckBox)

        outerLayout = QGridLayout()
        outerLayout.addWidget(self.weekdayColorLabel, 0, 0, 1, 1)
        outerLayout.addWidget(self.weekdayColorCombo, 0, 1, 1, 1)
        outerLayout.addWidget(self.weekendColorLabel, 1, 0, 1, 1)
        outerLayout.addWidget(self.weekendColorCombo, 1, 1, 1, 1)
        outerLayout.addWidget(self.headerTextFormatLabel, 2, 0, 1, 1)
        outerLayout.addWidget(self.headerTextFormatCombo, 2, 1, 1, 1)
        outerLayout.addLayout(checkBoxLayout, 3, 0, 1, 2)
        self.textFormatsGroupBox.setLayout(outerLayout)

        self.weekdayFormatChanged()
        self.weekendFormatChanged()

        self.reformatHeaders()
        self.reformatCalendarPage()

    def createColorComboBox(self):
        comboBox = QComboBox()
        comboBox.addItem("Red", Qt.red)
        comboBox.addItem("Blue", Qt.blue)
        comboBox.addItem("Black", Qt.black)
        comboBox.addItem("Magenta", Qt.magenta)
        return comboBox

    def applySetting(self):
        self.layout.setSpacing(2)
        self.layout.setSizeConstraint(QLayout.SetFixedSize)
        self.setSizePolicy(SiPoMin, SiPoMin)

    def hideEvent(self, event):
        # self.specs.showState.emit(False)
        pass

    def closeEvent(self, event):
        self.showLayout.emit(self.key, 'hide')
        event.ignore()
Example #13
0
class PricePositionWin(QWidget):
    """ 价格净持仓窗口 """

    def __init__(self, *args, **kwargs):
        super(PricePositionWin, self).__init__(*args, **kwargs)
        """ UI部分 """
        layout = QVBoxLayout()
        layout.setContentsMargins(QMargins(0, 0, 0, 0))
        # 操作头
        title_layout = QHBoxLayout()
        title_layout.setAlignment(Qt.AlignLeft)
        title_layout.addWidget(QLabel("交易所:", self))
        self.exchange_combobox = QComboBox(self)
        title_layout.addWidget(self.exchange_combobox)
        title_layout.addWidget(QLabel("期货品种:", self))
        self.variety_combobox = QComboBox(self)
        self.variety_combobox.setMinimumWidth(100)
        title_layout.addWidget(self.variety_combobox)
        title_layout.addWidget(QLabel("合约:", self))
        self.contract_combobox = QComboBox(self)
        title_layout.addWidget(self.contract_combobox)
        title_layout.addWidget(QLabel("起始日期:"))
        self.start_date = QDateEdit(self)
        self.start_date.setDisplayFormat('yyyy-MM-dd')
        self.start_date.setCalendarPopup(True)
        title_layout.addWidget(self.start_date)
        title_layout.addWidget(QLabel("终止日期:"))
        self.end_date = QDateEdit(self)
        self.end_date.setDisplayFormat('yyyy-MM-dd')
        self.end_date.setCalendarPopup(True)
        title_layout.addWidget(self.end_date)

        self.analysis_button = QPushButton("开始分析", self)
        self.analysis_button.setEnabled(False)
        title_layout.addWidget(self.analysis_button)
        self.option_widget = TitleOptionWidget(self)
        self.option_widget.setLayout(title_layout)
        layout.addWidget(self.option_widget)

        # 图形表格拖动区
        splitter = QSplitter(Qt.Vertical, self)
        splitter.setContentsMargins(QMargins(10, 5, 10, 5))

        # 请求数据遮罩层(需放在splitter之后才能显示,不然估计是被splitter覆盖)
        self.loading_cover = LoadingCover()
        self.loading_cover.setParent(self)
        self.loading_cover.resize(self.parent().width(), self.parent().height())

        # 图形区
        self.loading_cover.show(text='正在加载资源')
        self.chart_container = ChartContainWidget(ChartSourceChannel(), 'file:/templates/price_position.html', self)
        self.chart_container.page().loadFinished.connect(self.page_load_finished)
        splitter.addWidget(self.chart_container)

        # 表格区
        self.table_widget = QWidget(self)
        table_layout = QVBoxLayout()
        table_layout.setContentsMargins(QMargins(0, 0, 0, 0))

        opt_widget = QWidget(self.table_widget)
        opt_lt = QHBoxLayout(opt_widget)
        opt_lt.setContentsMargins(0,0,0,0)
        opt_widget.setLayout(opt_lt)
        # 日期选择,全品种净持率查看
        self.all_date_edit = QDateEdit(self)
        self.all_date_edit.setCalendarPopup(True)
        self.all_date_edit.setDisplayFormat('yyyy-MM-dd')
        self.all_date_edit.setDate(QDate.currentDate())
        opt_lt.addWidget(self.all_date_edit)
        self.all_query_button = QPushButton('查询全净持率', self)
        opt_lt.addWidget(self.all_query_button)
        # 增加净持率
        self.add_net_rate = QPushButton('增加列', self)
        opt_lt.addWidget(self.add_net_rate)

        opt_lt.addStretch()
        # 导出数据按钮
        self.export_button = QPushButton('导出EXCEL', self)
        self.export_button.setEnabled(False)
        opt_lt.addWidget(self.export_button)
        opt_widget.setFixedHeight(30)
        table_layout.addWidget(opt_widget)
        self.data_table = QTableWidget(self)
        self.data_table.verticalHeader().hide()
        self.data_table.setFocusPolicy(Qt.NoFocus)
        self.data_table.setColumnCount(7)
        self.data_table.setHorizontalHeaderLabels(['日期', '收盘价', '总持仓', '多头', '空头', '净持仓', '净持仓率%'])
        self.data_table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.data_table.setSelectionBehavior(QAbstractItemView.SelectRows)
        self.data_table.setSelectionMode(QAbstractItemView.SingleSelection)
        table_layout.addWidget(self.data_table)
        # 全品种净持仓率显示表
        self.all_table = QTableWidget(self)
        self.all_table.hide()
        table_layout.addWidget(self.all_table)

        self.table_widget.setLayout(table_layout)
        splitter.addWidget(self.table_widget)
        splitter.setSizes([self.parent().height() * 0.6, self.parent().height() * 0.4])
        layout.addWidget(splitter)

        # 设置表行高,各行颜色
        self.data_table.verticalHeader().setDefaultSectionSize(18)  # 设置行高(与下行代码同时才生效)
        self.data_table.verticalHeader().setMinimumSectionSize(18)
        self.data_table.setAlternatingRowColors(True)
        self.data_table.setObjectName('dataTable')
        self.setStyleSheet(
            "#dataTable{selection-color:rgb(80,100,200);selection-background-color:rgb(220,220,220);"
            "alternate-background-color:rgb(230,254,238);gridline-color:rgb(60,60,60)}"
        )
        # 设置表头,表滚动条样式
        self.data_table.horizontalHeader().setStyleSheet(HORIZONTAL_HEADER_STYLE)
        self.data_table.horizontalScrollBar().setStyleSheet(HORIZONTAL_SCROLL_STYLE)
        self.data_table.verticalScrollBar().setStyleSheet(VERTICAL_SCROLL_STYLE)

        self.setLayout(layout)

        """ 业务逻辑部分 """
        self.query_type = 'contract'  # 当前查询的数据类型
        # 网管器
        self.network_manager = getattr(qApp, 'network')
        # 关联交易所变化信号
        self.exchange_combobox.currentTextChanged.connect(self.get_variety_with_exchange)
        # 关联品种变化信号
        self.variety_combobox.currentTextChanged.connect(self.get_contract_with_variety)
        # 关联合约变化的信号
        self.contract_combobox.currentTextChanged.connect(self.get_min_max_date_with_contract)
        # 添加交易所
        for exchange_item in EXCHANGES:
            self.exchange_combobox.addItem(exchange_item['name'], exchange_item['id'])
        # 关联开始计算按钮信号
        self.analysis_button.clicked.connect(self.get_analysis_data)
        # 关联导出数据信息
        self.export_button.clicked.connect(self.export_table_to_excel)
        # 查询全品种净持仓率的信号
        self.all_query_button.clicked.connect(self.to_query_all_position)
        # 增加净持率列的信号
        self.add_net_rate.setEnabled(False)
        self.add_net_rate.clicked.connect(self.to_add_new_column_rate)
        # 点击表头排序
        self.all_table.horizontalHeader().sectionClicked.connect(self.all_table_horizontal_clicked)

        self.current_table = 'single_contract'

    def all_table_horizontal_clicked(self, col):
        if col < 7:
            return
        self.all_table.sortItems(col)
        # 重新设置一下颜色
        for row in range(self.all_table.rowCount()):
            for col in range(self.all_table.columnCount()):
                item = self.all_table.item(row, col)
                if row % 2 == 0:
                    item.setBackground(QBrush(QColor(230, 254, 238)))
                else:
                    item.setBackground(QBrush(QColor(255, 255, 255)))

    def to_add_new_column_rate(self):  # 新增净持率列
        new_column_date = self.all_date_edit.text()
        self.show_loading("正在获取数据")
        url = SERVER_2_0 + 'dsas/price-position/?ds={}&de={}'.format(new_column_date, new_column_date)
        reply = self.network_manager.get(QNetworkRequest(QUrl(url)))
        reply.finished.connect(self.new_column_data_reply)

    def new_column_data_reply(self):
        reply = self.sender()
        self.loading_finished()
        if reply.error():
            logger.error('GET NEW COLUMN NET POSTION ERROR. STATUS:{}'.format(reply.error()))
        else:
            data = json.loads(reply.readAll().data().decode('utf8'))
            variety_data = data.get('data', None)
            if not variety_data:
                return
            current_columns = self.all_table.columnCount()
            self.all_table.insertColumn(current_columns)
            self.all_table.setHorizontalHeaderItem(current_columns, QTableWidgetItem(self.all_date_edit.text()))
            self.insert_column_data(variety_data)
        reply.deleteLater()

    def insert_column_data(self, data):  # 添加列数据
        # 过滤data数据
        data = list(filter(lambda x: x['variety_en'] == x['contract'], data))
        # 数据转为dict形式
        rate_data = {item['variety_en']: item for item in data}
        current_column = self.all_table.columnCount() - 1
        for row in range(self.all_table.rowCount()):
            row_item = self.all_table.item(row, 0)
            variety_en = row_item.data(Qt.UserRole)['variety_en']
            data_item = rate_data.get(variety_en)
            if not data_item:
                continue
            # 计算净持率
            a = float(data_item['net_position'].replace(',', ''))
            b = float(data_item['position_volume'].replace(',', ''))
            rate = f'{round(a * 100 / b, 2)}%' if b > 0 else '-'
            display = round(a * 100 / b, 2) if b > 0 else '-'

            new_item = QTableWidgetItem(rate)
            new_item.setTextAlignment(Qt.AlignCenter)
            new_item.setData(Qt.DisplayRole, display)
            self.all_table.setItem(row, current_column, new_item)
            if row % 2 == 0:
                new_item.setBackground(QBrush(QColor(230, 254, 238)))

    def to_query_all_position(self):
        self.show_loading("正在获取数据")
        current_date = self.all_date_edit.text()
        url = SERVER_2_0 + 'dsas/price-position/?ds={}&de={}'.format(current_date, current_date)
        reply = self.network_manager.get(QNetworkRequest(QUrl(url)))
        reply.finished.connect(self.all_variety_position_reply)

    def all_variety_position_reply(self):
        reply = self.sender()
        self.loading_finished()
        if reply.error():
            logger.error('GET ALL VARIETY NET POSTION ERROR. STATUS:{}'.format(reply.error()))
        else:
            data = json.loads(reply.readAll().data().decode('utf8'))
            self.show_all_variety_net_position(data.get('data', []))
        reply.deleteLater()

    def show_all_variety_net_position(self, data):
        # 过滤data数据
        show_list = list(filter(lambda x: x['variety_en'] == x['contract'], data))
        self.all_table.clear()
        titles = ['日期', '品种', '主力收盘价', '总持仓量', '前20多单量', '前20空单量', '前20净持仓', '净持率%']
        columns = ['quotes_date', 'variety_name', 'close_price', 'position_volume', 'long_position', 'short_position',
                   'net_position', 'net_rate']

        self.all_table.setRowCount(len(show_list))
        self.all_table.setColumnCount(len(columns))
        self.all_table.setHorizontalHeaderLabels(titles)
        for row, p_item in enumerate(show_list):
            print(p_item)
            for col, key in enumerate(columns):
                if key == 'net_rate':
                    a = float(p_item['net_position'].replace(',', ''))
                    b = float(p_item['position_volume'].replace(',', ''))
                    rate = f'{round(a * 100 / b, 2)}%' if b > 0 else '-'
                    item = QTableWidgetItem(rate)
                    display = round(a * 100 / b, 2) if b > 0 else '-'
                    item.setData(Qt.DisplayRole, display)
                else:
                    item = QTableWidgetItem(str(p_item[key]))
                item.setTextAlignment(Qt.AlignCenter)
                if row % 2 == 0:
                    item.setBackground(QBrush(QColor(230, 254, 238)))
                if col == 0:
                    item.setData(Qt.UserRole, {'variety_en': p_item['variety_en']})
                self.all_table.setItem(row, col, item)

        self.data_table.hide()
        self.all_table.show()
        self.current_table = 'all_variety'
        if len(show_list) > 0:
            self.export_button.setEnabled(True)
            self.add_net_rate.setEnabled(True)

    def resizeEvent(self, event):
        super(PricePositionWin, self).resizeEvent(event)
        self.loading_cover.resize(self.parent().width(), self.parent().height())

    def clear_contents(self):
        """ 清除图形和表格 """
        self.chart_container.clear_chart()
        self.data_table.clearContents()
        self.data_table.setRowCount(0)

    def show_loading(self, show_text):
        """ 显示正在请求数据 """
        # 请求数据
        self.loading_cover.show(text=show_text)
        self.analysis_button.setEnabled(False)
        self.export_button.setEnabled(False)
        self.clear_contents()

    def loading_finished(self):
        """ 请求数据结束 """
        self.loading_cover.hide()
        self.analysis_button.setEnabled(True)

    def page_load_finished(self):
        """ 页面加载完成 """
        # self.loading_cover.hide()
        pass

    def get_variety_with_exchange(self):
        """ 获取交易所下的所有品种 """
        self.show_loading("正在获取品种")
        url = SERVER_API + 'exchange-variety/?is_real=1&exchange={}'.format(self.exchange_combobox.currentData())
        reply = self.network_manager.get(QNetworkRequest(QUrl(url)))
        reply.finished.connect(self.exchange_variety_reply)

    def exchange_variety_reply(self):
        # 交易所品种返回
        reply = self.sender()
        if reply.error():
            logger.error('GET EXCHANGE VARIETY ERROR. STATUS:{}'.format(reply.error()))
        else:
            data = json.loads(reply.readAll().data().decode('utf8'))
            self.set_current_variety(data['varieties'])
        reply.deleteLater()

    def set_current_variety(self, varieties: list):
        """ 设置当前的品种 """
        self.variety_combobox.clear()
        for variety_item in varieties:
            self.variety_combobox.addItem(variety_item['variety_name'], variety_item['variety_en'])

    def get_contract_with_variety(self):
        """ 根据品种获取全部合约 """
        if not self.variety_combobox.currentData():
            return
        self.show_loading('正在获取合约')
        url = SERVER_API + 'price-position-contracts/?variety_en={}'.format(self.variety_combobox.currentData())
        reply = self.network_manager.get(QNetworkRequest(QUrl(url)))
        reply.finished.connect(self.variety_contracts_reply)

    def variety_contracts_reply(self):
        """ 品种的所有合约返回 """
        reply = self.sender()
        if reply.error():
            logger.error("GET CONTRACTS OF VARIETY ERROR. STATUS:{}".format(reply.error()))
        else:
            data = json.loads(reply.readAll().data().decode('utf8'))
            self.set_current_contract(data['contracts'])
        reply.deleteLater()

    def set_current_contract(self, contracts: list):
        self.contract_combobox.clear()
        # 将第一个合约进行英文与数字的分离
        if len(contracts) > 0:
            variety = [''.join(list(g)) for k, g in groupby(contracts[0]['contract'], key=lambda x: x.isdigit())]
            v = variety[0] if len(variety[0]) <= 2 else variety[0][:2]
            self.contract_combobox.addItem(v)
        for contract_item in contracts:
            self.contract_combobox.addItem(contract_item['contract'])

    def get_min_max_date_with_contract(self):
        """ 根据合约获取时间范围 """
        if not self.contract_combobox.currentText():
            return
        current_contract = self.contract_combobox.currentText()
        split_list = [''.join(list(g)) for k, g in groupby(current_contract, key=lambda x: x.isdigit())]
        if len(split_list) > 1:  # 查询的是合约
            self.query_type = 'contract'
            self.show_loading('正在获取日期范围')
            url = SERVER_API + 'price-position-dates/?contract={}'.format(self.contract_combobox.currentText())
            reply = self.network_manager.get(QNetworkRequest(QUrl(url)))
            reply.finished.connect(self.min_max_date_reply)
        else:  # 查询的是品种
            max_date = int(datetime.datetime.strptime(datetime.datetime.today().strftime('%Y-%m-%d'), '%Y-%m-%d').timestamp())
            min_date = int(datetime.datetime.strptime(str(datetime.datetime.today().year - 3), '%Y').timestamp())
            self.set_min_and_max_date(min_date, max_date)
            self.query_type = 'variety'
            self.loading_finished()  # 加载数据结束

    def min_max_date_reply(self):
        """ 日期值返回 """
        reply = self.sender()
        if reply.error():
            logger.error("GET MIN & MAX DATE WITH CONTRACT ERROR. STATUS:{}".format(reply.error()))
        else:
            data = json.loads(reply.readAll().data().decode('utf8'))
            min_max_date = data["dates"]
            self.set_min_and_max_date(min_max_date['min_date'], min_max_date['max_date'])
        reply.deleteLater()
        self.loading_finished()  # 加载数据结束

    def set_min_and_max_date(self, min_date: int, max_date: int):
        """ 设置最大最小日期 """
        if not min_date or not max_date:
            self.analysis_button.setEnabled(False)
            return
        min_date = datetime.datetime.fromtimestamp(min_date)
        max_date = datetime.datetime.fromtimestamp(max_date)
        q_min_date = QDate(min_date.year, min_date.month, min_date.day)
        q_max_date = QDate(max_date.year, max_date.month, max_date.day)
        self.start_date.setDateRange(q_min_date, q_max_date)
        self.start_date.setDate(q_min_date)
        self.end_date.setDateRange(q_min_date, q_max_date)
        self.end_date.setDate(q_max_date)
        self.analysis_button.setEnabled(True)

    def get_analysis_data(self):
        """ 获取结果数据 """
        if not self.contract_combobox.currentText():
            QMessageBox.information(self, '错误', '请先选择合约后再操作.')
            return
        self.show_loading('正在获取资源数据')
        min_date = int(datetime.datetime.strptime(self.start_date.text(), '%Y-%m-%d').timestamp())
        max_date = int(datetime.datetime.strptime(self.end_date.text(), '%Y-%m-%d').timestamp())
        if self.query_type == 'contract':
            url = SERVER_API + 'price-position/?contract={}&min_date={}&max_date={}'.format(
                self.contract_combobox.currentText(), min_date, max_date
            )
        elif self.query_type == 'variety':
            url = SERVER_2_0 + 'dsas/price-position/?ds={}&de={}&c={}'.format(
                self.start_date.text(), self.end_date.text(), self.contract_combobox.currentText()
            )
        else:
            return
        reply = self.network_manager.get(QNetworkRequest(QUrl(url)))
        reply.finished.connect(self.price_position_reply)

    def price_position_reply(self):
        """ 获取数据返回 """
        reply = self.sender()
        if reply.error():
            logger.error("GET PRICE-POSITION DATA ERROR. STATUS:{}".format(reply.error()))
        else:
            data = json.loads(reply.readAll().data().decode('utf8'))
            if self.query_type == 'variety':
                # 处理数据,由于新版接口与旧版不一致
                for item in data['data']:
                    item['date'] = item['quotes_date'].replace('-', '')
                    item['contract'] = item['variety_en']
                    item['empty_volume'] = float(item['position_volume'].replace(',', ''))
                    item['long_position'] = float(item['long_position'].replace(',', ''))
                    item['short_position'] = float(item['short_position'].replace(',', ''))
                    del item['quotes_ts']
                    del item['position_volume']
                    del item['net_position']
                    del item['quotes_date']
            self.set_current_data_to_table(data['data'].copy())  # 数据在表格展示
            self.export_button.setEnabled(True)
            # 组合基本配置信息和源数据传递到页面
            base_option = {
                'title': '{}价格与净持率趋势图'.format(self.contract_combobox.currentText())
            }
            self.set_current_chart_to_page(json.dumps(data['data']), json.dumps(base_option))
        reply.deleteLater()
        self.loading_finished()

    def set_current_data_to_table(self, data_items: list):
        """ 将数据在表格显示 """
        self.data_table.clearContents()
        self.data_table.setRowCount(len(data_items))
        data_items.reverse()
        for row, row_item in enumerate(data_items):
            t_item0 = QTableWidgetItem(row_item['date'])
            t_item0.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, 0, t_item0)
            t_item1 = QTableWidgetItem(str(row_item['close_price']))
            t_item1.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, 1, t_item1)
            t_item2 = QTableWidgetItem(str(row_item['empty_volume']))
            t_item2.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, 2, t_item2)
            t_item3 = QTableWidgetItem(str(row_item['long_position']))
            t_item3.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, 3, t_item3)
            t_item4 = QTableWidgetItem(str(row_item['short_position']))
            t_item4.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, 4, t_item4)
            t_item5 = QTableWidgetItem(str(row_item['long_position'] - row_item['short_position']))
            t_item5.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, 5, t_item5)
            rate = '-' if row_item['empty_volume'] == 0 else str(
                round((row_item['long_position'] - row_item['short_position']) * 100 / row_item['empty_volume'], 2))
            t_item6 = QTableWidgetItem(rate)
            t_item6.setTextAlignment(Qt.AlignCenter)
            self.data_table.setItem(row, 6, t_item6)

        self.current_table = 'single_contract'
        self.data_table.show()
        self.all_table.hide()

    def set_current_chart_to_page(self, source_data: str, base_option: str):
        """ 设置数据到图形区域 """
        self.chart_container.set_chart_option(source_data, base_option)

    def export_table_to_excel(self):
        """ 导出表格数据到excel"""
        if self.current_table == 'single_contract':
            # 1 读取表格数据:
            table_df = self.read_table_data()
            # 2 选定保存的位置
            # 保存的文件名称
            filename = '{}价格-净持率数据'.format(self.contract_combobox.currentText())
            filepath, _ = QFileDialog.getSaveFileName(self, '保存文件', filename, 'EXCEL文件(*.xlsx *.xls)')
            if filepath:
                # 3 导出数据
                writer = pd.ExcelWriter(filepath, engine='xlsxwriter', datetime_format='YYYY-MM-DD')
                table_df.to_excel(writer, sheet_name='价格-净持率', index=False, encoding='utf8')
                writer.save()
        if self.current_table == 'all_variety':
            df = self.read_all_table_data() # 读取全品种表格的数据
            # 2 选定保存的位置
            # 保存的文件名称
            filename = '{}全品种价格-净持率数据'.format(self.all_date_edit.text())
            filepath, _ = QFileDialog.getSaveFileName(self, '保存文件', filename, 'EXCEL文件(*.xlsx *.xls)')
            if filepath:
                # 3 导出数据
                writer = pd.ExcelWriter(filepath, engine='xlsxwriter', datetime_format='YYYY-MM-DD')
                df.to_excel(writer, sheet_name='全品种价格-净持率', index=False, encoding='utf8')
                writer.save()

    def read_all_table_data(self):
        header_list = []
        value_list = []
        for header_col in range(self.all_table.columnCount()):
            header_list.append(
                self.all_table.horizontalHeaderItem(header_col).text()
            )
        for row in range(self.all_table.rowCount()):
            row_list = []
            for col in range(self.all_table.columnCount()):
                item_value = self.all_table.item(row, col).text()
                try:
                    value = datetime.datetime.strptime(item_value, '%Y%m%d') if col == 0 else float(
                        self.all_table.item(row, col).text())
                except ValueError:
                    value = item_value
                row_list.append(value)
            value_list.append(row_list)
        return pd.DataFrame(value_list, columns=header_list)

    def read_table_data(self):
        """ 读取表格数据 """
        header_list = []
        value_list = []
        for header_col in range(self.data_table.columnCount()):
            header_list.append(
                self.data_table.horizontalHeaderItem(header_col).text()
            )
        for row in range(self.data_table.rowCount()):
            row_list = []
            for col in range(self.data_table.columnCount()):
                item_value = self.data_table.item(row, col).text()
                try:
                    value = datetime.datetime.strptime(item_value, '%Y%m%d') if col == 0 else float(
                        self.data_table.item(row, col).text())
                except ValueError:
                    value = item_value
                row_list.append(value)
            value_list.append(row_list)
        return pd.DataFrame(value_list, columns=header_list)