in general, i want connect to the database selected by users.
i using 2 module, dblogin.py and xconn.py
dblogin.py is the gui for user to setting the desired dataname, and xconn.py is the connection to the postgresql
the problem is i can't get the value of dbedit in dblogin.py
how i can fix it?
thanks b4 for the answer.... Gbu all......
Regards,
ide
dblogin.py
class dblog(QDialog):
def __init__(self):
super(dblog, self).__init__()
self.dblabel = QLabel('Database Name')
self.dbedit = QLineEdit('')
#create button
...
#set layout in grid
#action for button
self.connect(self.connectbutton, SIGNAL('clicked()'),self.connectaction)
def connectaction(self):
self._data = self.dbedit.text()
if self._data == '':
_msg = QMessageBox.information(self,'information','Nama Database harus diisi !',QMessageBox.Ok)
self.dbedit.setFocus()
else:
try:
xconn.getconn()
_msg = QMessageBox.information(self,'information','Tunggu, Check database struktur!',QMessageBox.Ok)
except:
_msg = QMessageBox.information(self,'information','Database tidak ditemukan !',QMessageBox.Ok)
xconn.py
import psycopg2
import dblogin
def getconn():
_host = '127.0.0.1'
_user = 'postgres'
_pass = 'xxx'
_data = dblogin.dblog.getdb()
conn = psycopg2.connect(database=_data, user=_user, password=_pass, host=_host)
return conn
Your QDialog class should begin with capiatlized letters class DBLog. You can use the standardbuttons:
self.buttonBox = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel)
To set the text from the QLineEdit as return value, reimplement the accept method:
self.buttonBox.accepted.connect(self.accept)
def accept(self):
self._data = self.dbedit.text()
self.done(1)
Then in xconn create an instance od DBLog and only use the Dialog to get this value. Then from xconn.py do something like this:
dblog = DBLog() # create an instance for your dialog
if dblog:
_data = dblog._data
else:
Dialog not accepted
Related
Please be kind. This is my first question. I have included a minimum listing that illustrates the problem.
from PyQt5 import QtWidgets, QtCore, QtGui, uic, QtSql
from PyQt5.QtCore import Qt
qtCreatorFile = "QuotesGui.ui"
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
class QuotesUI(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, model):
QtWidgets.QMainWindow.__init__(self)
uic.loadUi(qtCreatorFile,self)
self.setupUi(self)
self.model = model # View owns the model
self.tableView.setModel(self.model._formModel)
self.setWidgetMapping() # Map model to view widgets
authorSRD = QtSql.QSqlRelationalDelegate(self.authorComboBox)
self.authorComboBox.setModel(self.model._authorModel)
self.authorComboBox.setItemDelegate(authorSRD)
self.authorComboBox.setModelColumn(
self.model._formModel.fieldIndex("authorName"))
citationSRD = QtSql.QSqlRelationalDelegate(self.citationComboBox)
self.citationComboBox.setModel(self.model._citationModel)
self.citationComboBox.setItemDelegate(citationSRD)
self.citationComboBox.setModelColumn(
self.model._formModel.fieldIndex("citationText"))
self.mainMapper.toFirst()
self._updateButtons(0) # To disable the previous button at start up
self.saveBtn.setEnabled(False) # Since we can't edit, we can't save
self._connectSignals(self.model)
def setWidgetMapping(self):
self.mainMapper = QtWidgets.QDataWidgetMapper(self)
self.mainMapper.setModel(self.model._formModel)
self.mainMapper.setItemDelegate(QtSql.QSqlRelationalDelegate(self))
self.mainMapper.addMapping(self.authorComboBox,
self.model._formModel.fieldIndex("authorName"))
self.mainMapper.addMapping(self.citationComboBox,
self.model._formModel.fieldIndex("citationText"))
self.mainMapper.addMapping(self.quoteText,
self.model._formModel.fieldIndex("quoteText"))
def _connectSignals(self, model):
self.lastBtn.clicked.connect(self.mainMapper.toLast)
self.nextBtn.clicked.connect(self.mainMapper.toNext)
self.prevBtn.clicked.connect(self.mainMapper.toPrevious)
self.firstBtn.clicked.connect(self.mainMapper.toFirst)
self.mainMapper.currentIndexChanged.connect(
self._updateButtons)
def _updateButtons(self, row):
self.firstBtn.setEnabled(row > 0)
self.prevBtn.setEnabled(row > 0)
self.nextBtn.setEnabled(row < self.model._formModel.rowCount() - 1)
self.lastBtn.setEnabled(row < self.model._formModel.rowCount() - 1)
class QuoteModel():
def __init__(self, data):
# Make a database connection
self.db = self.createConnection(data)
# set models
self._setFormModel()
self._setAuthorComboTableLink()
self._setCitationComboTableLink()
# Connect signals
self._connectSignals()
# Define a model for the form
def _setFormModel(self):
self._formModel = QtSql.QSqlRelationalTableModel(
parent = None, db = self.db)
self._formModel.setEditStrategy(
QtSql.QSqlTableModel.OnManualSubmit)
self._formModel.setTable("Quote")
authorIdx = self._formModel.fieldIndex("authorId")
citationIdx = self._formModel.fieldIndex("citationId")
self._formModel.setJoinMode(1) # Left Join
self._formModel.setRelation(authorIdx, QtSql.QSqlRelation(
"Author", "authorId", "authorName"))
self._formModel.setRelation(citationIdx, QtSql.QSqlRelation(
"Citation", "citationId", "citationText"))
self._formModel.select()
# Define models and link tables for the two comboboxes
def _setAuthorComboTableLink(self):
self._authorModel = QtSql.QSqlTableModel(
parent = None, db = self.db)
self._authorModel.setTable("Author")
self._authorModel.setEditStrategy(
QtSql.QSqlTableModel.OnManualSubmit)
self._authorModel.select()
self._authorModel.sort(1,Qt.AscendingOrder)
def _setCitationComboTableLink(self):
self._citationModel = QtSql.QSqlTableModel(
parent = None, db = self.db)
self._citationModel.setTable("Citation")
self._citationModel.setEditStrategy(
QtSql.QSqlTableModel.OnManualSubmit)
self._citationModel.select()
self._citationModel.sort(1,Qt.AscendingOrder)
def _newData(self):
print('in _newData')
def _connectSignals(self):
self._authorModel.rowsInserted.connect(self._newData)
#######################################################
# A function to connect to a named database
def createConnection(self,dbfile):
db = QtSql.QSqlDatabase.addDatabase('QSQLITE')
db.setDatabaseName(dbfile)
db.open()
if not db.open():
QtWidgets.QMessageBox.critical(
None, QtWidgets.qApp.tr("Cannot open database"),
QtWidgets.qApp.tr("Unable to establish a database connection.\n"),
QtWidgets.QMessageBox.Cancel,
)
return False
return db
dbFile = "Quotations.db"
if __name__=='__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
m = QuoteModel(dbFile)
w = QuotesUI(m)
w.show()
sys.exit(app.exec_())
Still requires the upload of a 8kb .ui file and a 70kb sample database to run. So far I haven't been able to figure out how to do that....
When this is run, incorporating the rest of the necessary code, the author combobox works as expected, i.e.: the dropdown shows all the values in the author table and when I step the the records in the model, the correct author is displayed in the combobox.
The citation combobox does NOT function. As written here it neither shows values from the citation table, nor is it connected to the quotes table. Basically it shows nothing.
I think I need, somehow, a second delegate on the model. But I don't know how.
Any ideas how to get this functioning??
To make this work I had to change:
self.authorComboBox.setModel(self.model._authorModel)
to:
authorRel = self.model._formModel.relationModel(self.model.authorIdx)
self.authorComboBox.setModel(authorRel)
The QSqlRelationalTableModel has a virtual function "relationModel" that returns a QSqlTableModel. When you use this model as the model for the QComboBox, everything works.
I'm trying to insert Date in my database table. but I got
Traceback (most recent call last):
File "D:\SchoolApp\Python\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
File "D:/SchoolApp/Python/register only.py", line 45, in register
self.entry_birthday = datetime.datetime(self.birth_day)
TypeError: an integer is required (got type IntVar)
I converted my variable self.get_birthday to int(self.get_birthday) but it's still an error.
Here's my code
import tkinter as tk
import pymysql
from tkinter import *
from tkinter import messagebox
import datetime
class Main(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
self.master = master
master.title("Thesis")
self.register_button = Button(master, text="Register", command=self.register)
self.register_button.pack()
self.db = pymysql.connect(host = "localhost",user = "root",passwd = "",db = "database")
self.cursor = self.db.cursor()
self.QueryResident = "CREATE TABLE IF NOT EXISTS residence (BIRTH_DATE date, AGE varchar(255)not null)"
self.cursor.execute(self.QueryResident)
def registered(self,birth_day):
self.get_birth_day =self.birth_day.get()
if (self.get_birth_day == ""):
messagebox.showerror("Error!","Please complete the required field")
else:
self.cursor.execute ("INSERT INTO residence (BIRTH_DATE) VALUES(%s)",(self.get_birth_day))
self.db.commit()
messagebox.showinfo("Success!","Registration successful")
self.cursor.close()
self.db.close()
def register(self):
self.master_register = Toplevel()
self.birth_day = IntVar()
self.label_birthday = Label(self.master_register, text = "Birth Day")
self.label_birthday.pack()
self.entry_birthday = Entry(self.master_register, textvariable = self.birth_day)
self.entry_birthday = datetime.datetime(self.birth_day)
self.entry_birthday.pack()
self.button_submit = Button(self.master_register, text = "Submit", command = lambda: self.registered(self.birth_day))
self.button_submit.pack()
My expected output is the inputted date get will store to a database in any date format and I will compute the age based on the given birth day.
Here some modifications to hopefully help you a little further. Basically you need to define how the date needs to be entered (so I choose a format yyyymmdd). Also best to enter as a StringVar. Then in the method registered parse the yyyymmdd into a datetime object, which you then can put into your database.
Using 'try-except' any date in the wrong format will not be accepted.
Code
import tkinter as tk
import pymysql
from tkinter import *
from tkinter import messagebox
import datetime
class Main(tk.Frame):
def __init__(self, master, *args, **kwargs):
tk.Frame.__init__(self, master, *args, **kwargs)
self.master = master
master.title("Thesis")
self.register_button = Button(master, text="Register", command=self.register)
self.register_button.pack()
self.db = pymysql.connect(host = "localhost",user = "root",passwd = "",db = "database")
self.cursor = self.db.cursor()
self.QueryResident = "CREATE TABLE IF NOT EXISTS residence (BIRTH_DATE date, AGE varchar(255)not null)"
self.cursor.execute(self.QueryResident)
def registered(self,birth_day):
birthday = self.birth_day.get()
try:
_year = int(birthday[0:4])
_month = int(birthday[4:6])
_day = int(birthday[6:8])
birthday = datetime.datetime(_year, _month, _day)
print(birthday) # for debugging purpose you can remove
except Exception as e:
print(e)
birthday = ""
if (birthday == ""):
messagebox.showerror("Error!","Please complete the required field")
else:
sql_string = "INSERT INTO residence (BIRTH_DATE) VALUES(%s)"
print(sql_string) # for debugging purpose you can remove
self.cursor.execute (sql_string,(birthday))
self.db.commit()
messagebox.showinfo("Success!","Registration successful")
self.cursor.close()
self.db.close()
def register(self):
self.master_register = Toplevel()
self.birth_day = StringVar()
self.label_birthday = Label(self.master_register, text = "Birth Day [yyyymmdd]")
self.label_birthday.pack()
self.entry_birthday = Entry(self.master_register, textvariable = self.birth_day)
self.entry_birthday.pack()
self.button_submit = Button(self.master_register, text = "Submit", command = lambda: self.registered(self.birth_day))
self.button_submit.pack()
root = Tk()
Main(root)
root.mainloop()
self.birth_day is an object, not an integer. Since it is an IntVar, you need to call the get method to retrieve the value.
datetime.datetime(self.birth_day.get())
I'm building a gui front-end for a project I've been working on, and I'm having trouble figuring out this specific aspect of PyQT. Long ago there was a post that I had that I think would've solved the problem but I can't quite find it.
Regardless, I have the following files, main.py and playlistcreator.py respectively:
(main.py)
import getpass
import playlistcreator
import os
import sys
import sip
sip.setapi('QString', 2)
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
# Window class
class Window(QWidget):
def __init__(self): # constructor for Window (passes "self" -aka Window- to __init__ to initialize it)
super(Window, self).__init__() # inherits from QMainWindow
self.setGeometry(50, 50, 300, 150) # Set window dimensions
self.setWindowTitle("Google Music Playlist Transfer") # Set window title
self.setWindowIcon(QIcon('gmusic.png')) # Set window icon
self.login = QWidget() # login widget ("front page")
self.processing = QWidget() # on successful login - being processing data
self.file_inputs = QWidget() # after processing, ask user where they would like to store data
# call functions
self.loginUI()
self.processingUI()
self.file_inputsUI()
# create stacked widget and add layouts to stack
self.Stack = QStackedWidget(self)
self.Stack.addWidget(self.login)
self.Stack.addWidget(self.processing)
self.Stack.addWidget(self.file_inputs)
main_box = QHBoxLayout(self)
main_box.addWidget(self.Stack)
self.setLayout(main_box)
self.show()
def loginUI(self):
# Set email field
self.email = QLineEdit()
self.email.setMaxLength(110)
self.email.setAlignment(Qt.AlignLeft)
# Set password field
self.pwd = QLineEdit()
self.pwd.setAlignment(Qt.AlignLeft)
self.pwd.setEchoMode(QLineEdit.Password)
# Form layout
form_layout = QFormLayout()
form_layout.addRow("Email: ", self.email)
form_layout.addRow("Password: ", self.pwd)
# Login button
self.login_btn = QPushButton("Login", self) # login button
self.login_btn.clicked.connect(self.process_login) # tell button what to do
self.login_btn.resize(self.login_btn.sizeHint())
# Quit button
self.quit_btn = QPushButton("Exit", self) # exit button
self.quit_btn.clicked.connect(self.close_application) # tell button what to do
# Error label layout
self.error_layout = QHBoxLayout()
# Button box layout
button_box = QHBoxLayout()
button_box.addStretch(1)
button_box.addWidget(self.login_btn)
button_box.addWidget(self.quit_btn)
# input layout (main layout for "home")
input_box = QVBoxLayout()
input_box.addLayout(self.error_layout)
input_box.addLayout(form_layout)
input_box.addLayout(button_box)
self.login.setLayout(input_box)
def processingUI(self):
# setup layout
layout = QHBoxLayout()
# alert user that we're grabbing track data
self.progress_label = QLabel("Grabbing tracks from Google Music. . .")
self.progress_label.setStyleSheet("color: rgb(0, 100, 0);")
layout.addWidget(self.progress_label)
# Get users list of "thumbs up" tracks from Google Music
# set layout
favorite_tracks = self.get_tracks
self.processing.setLayout(layout)
def file_inputsUI(self):
layout = QFormLayout()
# Set text field for directory
self.dir_textbox = QTextEdit(self)
# Add textbox to layout
layout.addRow("Music Directory: ", self.dir_textbox)
self.file_inputs.setLayout(layout)
def close_application(self):
confirm = QMessageBox.question(self, 'Exit Confirmation',
"Are you sure you want to exit?",
QMessageBox.Yes | QMessageBox.No)
if confirm == QMessageBox.Yes:
sys.exit()
else:
pass
def process_login(self):
email_input = str(self.email.text())
pwd_input = str(self.pwd.text())
login_successful = playlistcreator.login(email_input, pwd_input)
if login_successful:
self.Stack.setCurrentIndex(1)
else:
self.error_label = QLabel("Please check your email/password!")
self.error_label.setStyleSheet("color: rgb(255, 0, 0);")
self.error_layout.addWidget(self.error_label)
def get_tracks(self):
tracks = playlistcreator.get_favorite_tracks()
print("You have ", len(tracks), " favorite tracks!")
return tracks
# def open_dir_dialog(self):
# directory = QFileDialog.getExistingDirectory(self, 'Select USB Drive Location')
# self.myTextBox.setText(fileName)
def main():
# Create an PyQT5 application object.
app = QApplication(sys.argv)
GUI = Window()
sys.exit(app.exec_())
# # Input Music Directory
# music_dir = input("Please put the path to your music folder: ")
# list_of_paths = playlistcreator.findmp3(music_dir, favorite_tracks)
# # Input playlist file save location
# playlist_path = input("Where would you like to save the playlist?: ")
# playlist_name = input("What would you like to name the playlist? ")
# playlist_name += ".m3u8"
# # Testing appending file extension to string
# playlistcreator.addtoplaylist(list_of_paths, playlist_path, playlist_name)
# playlistcreator.logout()
main()
(playlistcreator.py)
import os
from gmusicapi import Mobileclient
from mutagen.easyid3 import EasyID3
api = Mobileclient()
songCount = 0
favorite_files_path = []
logged_in = False
def login(email, password):
library = []
if "#" not in email:
email += "#gmail.com"
logged_in = api.login(email, password, Mobileclient.FROM_MAC_ADDRESS)
return logged_in
def get_favorite_tracks():
print("Getting songs from Google Music. . .")
library = api.get_all_songs()
print("There are", len(library), "items in your music library")
good_songs = [song for song in library if song['rating'] == '5']
print("You have", len(good_songs), "favorite tracks!")
return good_songs
def logout():
api.logout()
def findmp3(rootFolder, favoriteTracks):
print("Searching for favorite tracks. . .")
for directory, subdirectory, files in os.walk(rootFolder, topdown=False): # for all files in directory
global songCount
global favorite_files_path
for mp3 in files: # for files in
if mp3.endswith(".mp3"): # if file ends with .mp3
file_path = os.path.join(directory, mp3) # concatenate to create full path
try:
file_tags = EasyID3(file_path) # grab file tags from mp3 file
except:
file_tags = EasyID3() # create tags if none are found
file_tags.save(file_path) # save file to have new tags
if "title" in file_tags:
fileTitle = file_tags["title"][0] # TIT2 = corresponding tag in mutagen for song title
else:
fileTitle = "None"
if "artist" in file_tags:
fileArtist = file_tags["artist"][0] # TPE = corresponding tag in mutagen for artist
else:
fileArtist = "None"
if "album" in file_tags:
fileAlbum = file_tags["album"][0] # TALB = corresponding tag in mutagen for album
else:
fileAlbum = "None"
for track in favoriteTracks:
gMusicTitle = track["title"]
gMusicArtist = track["artist"]
gMusicAlbum = track["album"]
if fileTitle in gMusicTitle and fileArtist in gMusicArtist and fileAlbum in gMusicAlbum: # if file tags (artist, album, title) match gMusic tags
songCount += 1
if songCount == 1:
print("Found 1 song")
else:
print("Found", songCount, "songs") # print updated count of found tracks
favorite_files_path.append(file_path) # add all found files to a list (via their paths)
break # break out of "for track in favorite tracks"
return favorite_files_path
def addtoplaylist(paths, playlist_path, playlist_name):
# Open file (or create if it does not exist)
# change to given directory
try:
os.chdir(playlist_path)
except Exception as err:
print(err)
# open file - if it does not exist, create it
with open(playlist_name, 'a+', encoding="UTF-8") as playlistFile:
print("Adding tracks...", end="")
for track in paths:
print(".", end="")
playlistFile.write(track + '\n')
playlistFile.close()
The problem I've been running into is when the user logs in they hit the processingUI window (which states that the program is grabbing all their tracks from Google) but it doesn't actually seem to be running the get_tracks() method (which is what actually gets the user's tracks from Google), as the program hangs there and doesn't do anything.
I've tested the program without a GUI using straight command line, and it works flawlessly, but I'm not sure what the issue is with the GUI - do I need to thread the execution to start when the proper "window" is brought to the front?
I have two python files, the first one is to handle database related stuff and the second one imports that file so I can use it with PyQt.
The problem is if I want to change the label in the first file it doesn't work the application just crashes.
The reason I want the first file to be able to change the label is if an error occurs when trying to connect to the DB.
Here is a short view of my code:
First file.
from mysql.connector import (connection)
from datetime import *
from RPI1_ui import Ui_Form
'''Handling of database related stuff'''
class DatabaseUtility(Ui_Form):
def __init__(self):
#DB Connection
self.cnx = None
self.cursor = None
def mysql_connect(self):
# Database connection
try:
self.cnx = connection.MySQLConnection(user='root', password='', host='127.0.0.1', database='spicadb')
self.cursor = self.cnx.cursor()
except connection.errors.InterfaceError as e:
self.lblShowInfo.setText(str(e)) # -> Try to change label
def get_table(self):
return self.run_command("SELECT * FROM tblseal")
def get_columns(self):
return self.run_command("SHOW COLUMNS FROM tblseal")
Second file.
from PyQt5.QtWidgets import QApplication, QWidget, QDialog
from datetime import *
from bs4 import BeautifulSoup as bs
import os
import sys
import DatabaseHandling
'''Convert UI file to Python'''
os.chdir("C:\\Users\Gianni Declercq\AppData\Local\Programs\Python\Python36-32\Scripts")
os.system("pyuic5.exe H:\QtProjects\\RPI1.ui -o H:\QtProjects\\RPI1_ui.py")
from RPI1_ui import Ui_Form # import after recreation of py file
from RPI1_Sec import SecondWindow
'''Main program'''
class MainWindow(QWidget, Ui_Form):
def __init__(self):
super(MainWindow, self).__init__()
# Initialize variables
self.dbu = DatabaseHandling.DatabaseUtility()
self.spica_reference = None
self.barcode = None
self.msl = None
self.package_body = None
self.window2 = None
# Get UI elements + resize window
self.setupUi(self)
self.resize(800, 480)
# Define what should happen on button click
self.btnQuit.clicked.connect(lambda: app.exit())
self.btnInsert.clicked.connect(lambda: self.get_entry())
self.btnTable.clicked.connect(lambda: self.new_window())
# Style buttons
self.btnQuit.setStyleSheet("background-color: red")
self.btnInsert.setStyleSheet("background-color: green")
self.btnTable.setStyleSheet("background-color: orange")
def get_entry(self):
try:
self.spica_reference = self.txtReferentie.text()
self.barcode = self.txtBarcode.text()
self.msl = self.txtMsl.text()
self.package_body = float(self.txtBodyPackage.text())
except ValueError:
self.lblShowInfo.setText("Please insert the correct values")
self.lblShowInfo.setStyleSheet('color: red')
else:
self.dbu.mysql_connect()
if self.dbu.cursor and self.dbu.cnx is not None:
self.dbu.add_entry(self.spica_reference, self.barcode, self.msl, self.package_body, self.calc_floor_life)
Give a "hook function" to the DatabaseUtility when initializing.
class MainWindow(QWidget, Ui_Form):
def __init__():
def ch_lab(text):
self.lblShowInfo.setText(text)
self.dbu = DatabaseHandling.DatabaseUtility(ch_lab)
class DatabaseUtility(Ui_Form):
def __init__(cb):
self.error_warn = cb
#.. error happening
self.error_warn('error')
I have the same problem mentioned here : Not being able to edit NSTextField on NSPopover even though Editable behavior is set. The solution seems to be to override the canBecomeKeyWindow of NSWindow. I am trying to do the same thing in PyObjC, but I am getting an error Python signature doesn't match implied objective-C signature.
In the following code, if I comment out canBecomeKeyWindow_(), then the app runs as expected, but I am not able to click and edit the textfields.
# from Cocoa import *
from AppKit import NSWindowController, NSApplication, NSApp, NSMaxYEdge, NSImage, NSStatusBar, NSMenu, NSMenuItem, NSVariableStatusItemLength, NSRect
from Cocoa import objc
from Foundation import NSUserNotification, NSUserNotificationCenter, NSObject
from PyObjCTools import AppHelper
import webbrowser
import subprocess
import os
global popover
class TestApp(NSApplication):
def finishLaunching(self):
# Make statusbar item
statusbar = NSStatusBar.systemStatusBar()
self.statusitem = statusbar.statusItemWithLength_(NSVariableStatusItemLength)
self.icon = NSImage.alloc().initByReferencingFile_('app-icon.png')
self.icon.setScalesWhenResized_(True)
self.icon.setSize_((20, 20))
self.statusitem.setImage_(self.icon)
self.statusitem.setHighlightMode_(1)
# make the menu
self.menubarMenu = NSMenu.alloc().init()
self.menuItem = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Login', 'loginCallback:', '')
self.menubarMenu.addItem_(self.menuItem)
self.quit = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_('Quit', 'terminate:', '')
self.menubarMenu.addItem_(self.quit)
# add menu to statusitem
self.statusitem.setMenu_(self.menubarMenu)
def loginCallback_(self, notification):
# Initiate the contrller with a XIB
viewController = SimpleXibDemoController.alloc().initWithWindowNibName_("Login")
# Show the window
viewController.showWindow_(viewController)
rect = self.statusitem.valueForKey_('button').frame()
viewController.popover.showRelativeToRect_ofView_preferredEdge_(rect, self.statusitem.valueForKey_('button'), NSMaxYEdge)
class SimpleXibDemoController(NSWindowController):
popover = objc.IBOutlet()
counterTextField = objc.IBOutlet()
username_field = objc.IBOutlet()
password_field = objc.IBOutlet()
submit_button = objc.IBOutlet()
def canBecomeKeyWindow_(self):
return 1
def windowDidLoad(self):
NSWindowController.windowDidLoad(self)
#objc.IBAction
def submit_(self, sender):
username = self.username_field.stringValue()
password = self.password_field.stringValue()
self.updateDisplay(username + ' ' + password)
def updateDisplay(self, value):
self.counterTextField.setStringValue_(value)
if __name__ == "__main__":
app = TestApp.sharedApplication()
icon = NSImage.alloc().initByReferencingFile_('app-icon.png')
app.setApplicationIconImage_(icon)
AppHelper.runEventLoop()
It looks like you're adding an underscore where you shouldn't. The PyObjC bridge will translate it into a colon. Besides that, the corresponding Python boolean value should be True. Thus, the correct function would look like this:
def canBecomeKeyWindow(self):
return True