QScintilla based text editor in PyQt5 with clickable functions and variables - python

I am trying to make a simple texteditor with basic syntax highlighting, code completion and clickable functions & variables in PyQt5. My best hope to achieve this is using the QScintilla port
for PyQt5.
I have found the following QScintilla-based texteditor example on the Eli Bendersky website (http://eli.thegreenplace.net/2011/04/01/sample-using-qscintilla-with-pyqt, Victor S. has adapted it to PyQt5). I think this example is a good starting point:
#-------------------------------------------------------------------------
# qsci_simple_pythoneditor.pyw
#
# QScintilla sample with PyQt
#
# Eli Bendersky (eliben#gmail.com)
# This code is in the public domain
#-------------------------------------------------------------------------
import sys
import sip
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.Qsci import QsciScintilla, QsciLexerPython
class SimplePythonEditor(QsciScintilla):
ARROW_MARKER_NUM = 8
def __init__(self, parent=None):
super(SimplePythonEditor, self).__init__(parent)
# Set the default font
font = QFont()
font.setFamily('Courier')
font.setFixedPitch(True)
font.setPointSize(10)
self.setFont(font)
self.setMarginsFont(font)
# Margin 0 is used for line numbers
fontmetrics = QFontMetrics(font)
self.setMarginsFont(font)
self.setMarginWidth(0, fontmetrics.width("00000") + 6)
self.setMarginLineNumbers(0, True)
self.setMarginsBackgroundColor(QColor("#cccccc"))
# Clickable margin 1 for showing markers
self.setMarginSensitivity(1, True)
# self.connect(self,
# SIGNAL('marginClicked(int, int, Qt::KeyboardModifiers)'),
# self.on_margin_clicked)
self.markerDefine(QsciScintilla.RightArrow,
self.ARROW_MARKER_NUM)
self.setMarkerBackgroundColor(QColor("#ee1111"),
self.ARROW_MARKER_NUM)
# Brace matching: enable for a brace immediately before or after
# the current position
#
self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
# Current line visible with special background color
self.setCaretLineVisible(True)
self.setCaretLineBackgroundColor(QColor("#ffe4e4"))
# Set Python lexer
# Set style for Python comments (style number 1) to a fixed-width
# courier.
#
lexer = QsciLexerPython()
lexer.setDefaultFont(font)
self.setLexer(lexer)
text = bytearray(str.encode("Arial"))
# 32, "Courier New"
self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, text)
# Don't want to see the horizontal scrollbar at all
# Use raw message to Scintilla here (all messages are documented
# here: http://www.scintilla.org/ScintillaDoc.html)
self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
# not too small
self.setMinimumSize(600, 450)
def on_margin_clicked(self, nmargin, nline, modifiers):
# Toggle marker for the line the margin was clicked on
if self.markersAtLine(nline) != 0:
self.markerDelete(nline, self.ARROW_MARKER_NUM)
else:
self.markerAdd(nline, self.ARROW_MARKER_NUM)
if __name__ == "__main__":
app = QApplication(sys.argv)
editor = SimplePythonEditor()
editor.show()
editor.setText(open(sys.argv[0]).read())
app.exec_()
Just copy-paste this code into an empty .py file, and run it. You should get the following simple texteditor appearing on your display:
Notice how perfect the syntax highlighting is! QScintilla certainly did some parsing on the background to achieve that.
Is it possible to make clickable functions & variables for this texteditor? Every self-respecting IDE has it. You click on a function, and the IDE jumps to the function definition. The same for variables. I would like to know:
Does QScintilla support clickable functions & variables?
If not, is it possible to import another python module that implements this feature in the QScintilla texteditor?
EDIT :
λuser noted the following:
Clickable function names require full parsing with a much deeper knowledge of a programming language [..]This is way beyond the scope of Scintilla/QScintilla. Scintilla provides a way to react when the mouse clicks somewhere on the text, but the logic of "where is the definition of a function" is not in Scintilla and probably never will be.However, some projects are dedicated to this task, like ctags. You could simply write a wrapper around this kind of tool.
I guess that writing such wrapper for ctags is now on my TODO list. The very first step is to get a reaction (Qt signal) when the user clicks on a function or variable. And perhaps the function/variable should turn a bit blueish when you hover with the mouse over it, to notify the user that it is clickable. I already tried to achieve this, but am held back by the shortage of QScintilla documentation.
So let us trim down the question to: How do you make a function or variable in the QScintilla texteditor clickable (with clickable defined as 'something happens')
EDIT :
I just returned to this question now - several months later. I have been cooperating with my friend Matic Kukovec to design a website about QScintilla. It is a beginner-friendly tutorial on how to use it:
https://qscintilla.com/
I hope this initiative fills the gap of lacking documentation.

Syntax highlighting is just a matter of running a lexer on the source file to find tokens, then attribute styles to it. A lexer has a very basic understanding of a programming language, it only understands what is a number literal, a keyword, an operator, a comment, a few others and that's all. This is a somewhat simple job that can be performed with just regular expressions.
On the other hand, clickable function names requires requires full parsing with a much deeper knowledge of a programming language, e.g. is this a declaration of a variable or a use, etc. Furthermore, this may require parsing other source files not opened by current editor.
This is way beyond the scope of Scintilla/QScintilla. Scintilla provides a way to react when the mouse clicks somewhere on the text, but the logic of "where is the definition of a function" is not in Scintilla and probably never will be.
However, some projects are dedicated to this task, like ctags. You could simply write a wrapper around this kind of tool.

A way to use Pyqt5 with option with clickable functions and variables.
Your script that have the clickable part Quoted out, would look like this in PyQt5 with a custom signal.
PyQt4 SIGNAL
self.connect(self,SIGNAL('marginClicked(int, int, Qt::KeyboardModifiers)'),
self.on_margin_clicked)
PyQt5 SIGNAL
self.marginClicked.connect(self.on_margin_clicked)
PyQt5
import sys
import sip
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.Qsci import QsciScintilla, QsciLexerPython
class SimplePythonEditor(QsciScintilla):
ARROW_MARKER_NUM = 8
def __init__(self, parent=None):
super(SimplePythonEditor, self).__init__(parent)
# Set the default font
font = QFont()
font.setFamily('Courier')
font.setFixedPitch(True)
font.setPointSize(10)
self.setFont(font)
self.setMarginsFont(font)
# Margin 0 is used for line numbers
fontmetrics = QFontMetrics(font)
self.setMarginsFont(font)
self.setMarginWidth(0, fontmetrics.width("00000") + 6)
self.setMarginLineNumbers(0, True)
self.setMarginsBackgroundColor(QColor("#cccccc"))
# Clickable margin 1 for showing markers
self.setMarginSensitivity(1, True)
self.marginClicked.connect(self.on_margin_clicked)
self.markerDefine(QsciScintilla.RightArrow,
self.ARROW_MARKER_NUM)
self.setMarkerBackgroundColor(QColor("#ee1111"),
self.ARROW_MARKER_NUM)
# Brace matching: enable for a brace immediately before or after
# the current position
#
self.setBraceMatching(QsciScintilla.SloppyBraceMatch)
# Current line visible with special background color
self.setCaretLineVisible(True)
self.setCaretLineBackgroundColor(QColor("#ffe4e4"))
# Set Python lexer
# Set style for Python comments (style number 1) to a fixed-width
# courier.
#
lexer = QsciLexerPython()
lexer.setDefaultFont(font)
self.setLexer(lexer)
text = bytearray(str.encode("Arial"))
# 32, "Courier New"
self.SendScintilla(QsciScintilla.SCI_STYLESETFONT, 1, text)
# Don't want to see the horizontal scrollbar at all
# Use raw message to Scintilla here (all messages are documented
# here: http://www.scintilla.org/ScintillaDoc.html)
self.SendScintilla(QsciScintilla.SCI_SETHSCROLLBAR, 0)
# not too small
self.setMinimumSize(600, 450)
def on_margin_clicked(self, nmargin, nline, modifiers):
# Toggle marker for the line the margin was clicked on
if self.markersAtLine(nline) != 0:
self.markerDelete(nline, self.ARROW_MARKER_NUM)
else:
self.markerAdd(nline, self.ARROW_MARKER_NUM)
if __name__ == "__main__":
app = QApplication(sys.argv)
editor = SimplePythonEditor()
editor.show()
editor.setText(open(sys.argv[0]).read())
app.exec_()

I got a helpful answer from Matic Kukovec through mail, that I would like to share here. Matic Kukovec made an incredible IDE based on QScintilla: https://github.com/matkuki/ExCo. Maybe it will inspire more people to dig deeper into QScintilla (and clickable variables and functions).
Hotspots make text clickable. You have to style it manualy using the QScintilla.SendScintilla function.
Example function I used in my editor Ex.Co. ( https://github.com/matkuki/ExCo ):
def style_hotspot(self, index_from, length, color=0xff0000):
"""Style the text from/to with a hotspot"""
send_scintilla =
#Use the scintilla low level messaging system to set the hotspot
self.SendScintilla(PyQt4.Qsci.QsciScintillaBase.SCI_STYLESETHOTSPOT, 2, True)
self.SendScintilla(PyQt4.Qsci.QsciScintillaBase.SCI_SETHOTSPOTACTIVEFORE, True, color)
self.SendScintilla(PyQt4.Qsci.QsciScintillaBase.SCI_SETHOTSPOTACTIVEUNDERLINE, True)
self.SendScintilla(PyQt4.Qsci.QsciScintillaBase.SCI_STARTSTYLING, index_from, 2)
self.SendScintilla(PyQt4.Qsci.QsciScintillaBase.SCI_SETSTYLING, length, 2)
This makes text in the QScintilla editor clickable when you hover the mouse over it.
The number 2 in the above functions is the hotspot style number.
To catch the event that fires when you click the hotspot, connect to these signals:
QScintilla.SCN_HOTSPOTCLICK
QScintilla.SCN_HOTSPOTDOUBLECLICK
QScintilla.SCN_HOTSPOTRELEASECLICK
For more details look at Scintilla hotspot documentation:
http://www.scintilla.org/ScintillaDoc.html#SCI_STYLESETHOTSPOT
and QScintilla hotspot events:
http://pyqt.sourceforge.net/Docs/QScintilla2/classQsciScintillaBase.html#a5eff383e6fa96cbbaba6a2558b076c0b
First of all, a big thank you to Mr. Kukovec! I have a few questions regarding your answer:
(1) There are a couple of things I don't understand in your example function.
def style_hotspot(self, index_from, length, color=0xff0000):
"""Style the text from/to with a hotspot"""
send_scintilla = # you undefine send_scintilla?
#Use the scintilla low level messaging system to set the hotspot
self.SendScintilla(..) # What object does 'self' refer to in this
self.SendScintilla(..) # context?
self.SendScintilla(..)
(2) You say "To catch the event that fires when you click the hotspot, connect to these signals:"
QScintilla.SCN_HOTSPOTCLICK
QScintilla.SCN_HOTSPOTDOUBLECLICK
QScintilla.SCN_HOTSPOTRELEASECLICK
How do you actually connect to those signals? Could you give one example? I'm used to the PyQt signal-slot mechanism, but I never used it on QScintilla. It would be a big help to see an example :-)
(3) Maybe I missed something, but I don't see where you define in QScintilla that functions and variables (and not other things) are clickable in the source code?
Thank you so much for your kind help :-)

Have a look at the following documentation:
https://qscintilla.com/#clickable_text
There are two ways to make things clickable in Qscintilla - you can use hotspots or indicators. hotspots require you to override the default behavior of underlying lexer, but indicators are more convenient for your use case, I think.
I suggest you have a look at indicators which can help you to make text clickable and you can define event handlers that get executed when it gets clicked.
https://qscintilla.com/#clickable_text/indicators

Related

PYQT5 QRadioButton, QCheckBox color

I'm using radio buttons and checkboxes and I was wondering if there was a way to change the color of the border around the checkmark/radio indications. The reason is because when I switch to dark mode on my layout, the border is no longer visible.
By going to dark mode, I just inverse the foreground and background colors.
class ChannelWindow(QWidget):
"""channel real-time display class (used for both default and custom types)"""
def __init__(self, channel, this_type, comPort, spot):
super().__init__()
self.setGeometry(myWin.pos().x() - 535 + spot, myWin.pos().y() + 31, 520, 775)
self.setWindowTitle(f"{channel} Data Window")
self.setWindowIcon(QtGui.QIcon('files/images/ham.ico'))
self.setStyleSheet(f"color: {foreground}; background-color: {background}")
Setting a basic stylesheet alone is insufficient, unless you are really thorough. Most of the times, its results are inconsistent.
There are two reasons for that:
Qt uses QStyle to draw widgets, compute their sizes, position child elements (like the indicator of a QCheckBox) and properly draw them;
QSS (Qt Style Sheets) are propagating (since they follow the cascading feature of CSS) and require specific selectors for sub-controls of complex widgets; setting style sheet makes Qt use an internal QStyle (QStyleSheetStyle) that sometimes completely overrides the default behavior of the basic style;
Most importantly, complex widgets usually require to write the full specifications of their contents, especially for sub-controls; and using generic properties is always discouraged for such widgets (including doing it for their parents).
There are various solutions to this, starting by using customized dark "themes" (see this post and the related answers). This has some caveats: it's actually a new style, so you might not like it, or would want to use custom style sheets that would create some compatibility issues.
The custom stylesheet solution, though, is quite more complex, as you should specify all sub controls colors, because even if you use class selectors, that won't be enough. For instance, QCheckBox requires that you specify the properties of ::indicator but, as explained above, once you set a property for a sub control, you must set all other properties along with it; in the case of QCheckBox this means that you have to write rules for all states (disabled, checked, unchecked, etc) and provide an image for the check mark symbol.
Other complex widgets (like scroll bars) require carefully written style sheets, otherwise they would look terrible.
You should also consider that some colors might not be compatible with the chosen ones (like the selection color).
A simpler (and, usually, more compliant) solution, is to set the application palette using the color constructor and eventually use carefully written style sheets to override some widget-specific colors if needed.
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
Palettes = []
class Widget(QWidget):
def __init__(self):
super().__init__()
self.setStyleSheet('''
QGroupBox::title {
color: red;
}
''')
layout = QVBoxLayout(self)
darkCheck = QCheckBox('Switch dark mode')
layout.addWidget(darkCheck)
# just some random widgets
group = QGroupBox('Hello!')
layout.addWidget(group)
groupLayout = QVBoxLayout(group)
groupLayout.addWidget(QTextEdit('lorem ipsum ' * 1000))
combo = QComboBox()
combo.addItems(('a', 'b', 'c'))
groupLayout.addWidget(combo)
groupLayout.addWidget(QLineEdit('line edit'))
darkCheck.clicked.connect(setDarkMode)
def setDarkMode(dark):
app = QApplication.instance()
if not Palettes:
Palettes.append(app.palette())
Palettes.append(QPalette(Qt.darkGray))
app.setPalette(Palettes[dark])
for window in QApplication.topLevelWidgets():
old = window.styleSheet()
if not old:
window.setStyleSheet(' ')
window.setStyleSheet(old)
if __name__ == "__main__":
app = QApplication(sys.argv)
test = Widget()
test.show()
sys.exit(app.exec())
As you can see, I altered the appearance of the group box title, but I specifically used a selector for the subcontrol of its class.
The last part is to ensure that all the top level widgets (and their children) compute again their stylesheets, even if they do not have any.

Maya Python: Button always at the center of the window

I'm starting experimenting with Maya python, and I'm trying to do some UI.
I came across to a really strange problem, I can't get a button to stay in the center of the windows.
I've tried different things but nothing seems to work, here is the code:
import maya.cmds as cmds
cmds.window( width=200 )
WS = mc.workspaceControl("dockName", retain = False, floating = True,mw=80)
submit_widget = cmds.rowLayout(numberOfColumns=1, p=WS)
cmds.button( label='Submit Job',width=130,align='center', p=submit_widget)
cmds.showWindow()
this is a simple version but still, I can't get it to work.
can someone help me?
I honestly don't know the answer as anytime I have to dig into Maya's native UI stuff it makes me question my own life.
So I know it's not exactly what you're asking for, but I'll opt with this: Use PySide instead. At first glance it might make you go "woah, that's way too hard", but it's also a million times better (and actually easier). It's much more powerful, flexible, has great documentation, and also used outside of Maya (so actually useful to learn). Maya's own interface uses the same framework, so you can even edit it with PySide once you're more comfortable with it.
Here's a bare-bones example to create a centered button in a window:
# Import PySide libraries.
from PySide2 import QtCore
from PySide2 import QtWidgets
class MyWindow(QtWidgets.QWidget): # Create a class for our window, which inherits from `QWidget`
def __init__(self, parent=None): # The class's constructor.
super(MyWindow, self).__init__(parent) # Initialize its `QWidget` constructor method.
self.my_button = QtWidgets.QPushButton("My button!") # Create a button!
self.my_layout = QtWidgets.QVBoxLayout() # Create a vertical layout!
self.my_layout.setAlignment(QtCore.Qt.AlignCenter) # Center the horizontal alignment.
self.my_layout.addWidget(self.my_button) # Add the button to the layout.
self.setLayout(self.my_layout) # Make the window use this layout.
self.resize(300, 300) # Resize the window so it's not tiny.
my_window_instance = MyWindow() # Create an instance of our window class.
my_window_instance.show() # Show it!
Not too bad, right?

How to make forcus highlight for 2 objects at the same time

I want both view below are blue, how to set it? please help me! when i forcus to the second line i want it highlight both of object are blue, not one blue and one grey as below.
Code like this:
ui = twin_gtk_builder('twin.ui', ['dia_support', 'liststore7'])
win = ui.get_object('dia_support')
##### Begin function tree view
liststore = gtk.ListStore(int, int, int)
liststore.append([1,2,3])
liststore.append([2,2,2])
liststore.append([4,4,4])
win.sw = gtk.ScrolledWindow()
win.sm = gtk.TreeModelSort(liststore)
##### Set sort column
n = 1
win.sm.set_sort_column_id(n, gtk.SORT_ASCENDING)
win.tv = gtk.TreeView(win.sm)
win.vbox.pack_start(win.sw)
win.sw.add(win.tv)
win.tv.column = [None] * 3
win.tv.column[0] = gtk.TreeViewColumn('0-1000')
win.tv.column[1] = gtk.TreeViewColumn('0-1000000')
win.tv.column[2] = gtk.TreeViewColumn('-10000-10000')
win.tv.cell = [None] * 3
for i in range(3):
win.tv.cell[i] = gtk.CellRendererText()
win.tv.append_column(win.tv.column[i])
win.tv.column[i].set_sort_column_id(i)
win.tv.column[i].pack_start(win.tv.cell[i], True)
win.tv.column[i].set_attributes(win.tv.cell[i], text=i)
##### End function tree view
win.show_all()
and how it work
Tried one more time with #PM 2Ring help, Thanks so much for your help!
Somebody did it like this, but i can't find his contact...
I had to do a bit of work to get that code to run, Sunshine jp. In future, please try to post code that others can run & test, especially if it's GUI code. Otherwise it can be very hard to work out what the problem is and how to fix it.
I'm not familiar with twin_gtk1_builder(). Is it a GTK1 function?
Anyway, I've modified your code to run on GTK2+. I'm not quite sure what you want your code to do. So I've given row 2 a background color of cyan. Also, I've added the ability to make multiple selections, either using Ctrl or Shift on the keyboard when you select with the mouse; you can also do multiple selection with the keyboard with shift up and down arrows.
When the window loses focus the selected row(s) stays blue on my system. Maybe that's a feature of GTK2 that GTK1 doesn't have. (Or maybe it's due to my window manager - I'm using KDE 4.5.3 on Mepis Linux).
#!/usr/bin/env python
'''
TreeView test
From http://stackoverflow.com/questions/25840091/how-to-make-forcus-highlight-for-2-objects-at-the-same-time
'''
import pygtk
#pygtk.require('2.0')
import gtk
def TreeViewTest():
def delete_event(widget, event, data=None):
gtk.main_quit()
return False
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.set_title("TreeView Test")
win.set_size_request(320, 160)
win.connect("delete_event", delete_event)
win.vbox = gtk.VBox()
win.add(win.vbox)
win.sw = gtk.ScrolledWindow()
win.vbox.pack_start(win.sw)
##### Begin function tree view
#Set up liststore data. Column 3 controls whether
# background color of the TreeView is default or special.
liststore = gtk.ListStore(int, int, int, bool)
liststore.append([1, 2, 3, False])
#Tell row 2 to use the special color
liststore.append([2, 2, 2, True])
liststore.append([4, 4, 4, False])
win.sm = gtk.TreeModelSort(liststore)
##### Set initial sort column
n = 1
win.sm.set_sort_column_id(n, gtk.SORT_ASCENDING)
win.tv = gtk.TreeView(win.sm)
win.sw.add(win.tv)
win.tv.column = [None] * 3
win.tv.column[0] = gtk.TreeViewColumn('0-1000')
win.tv.column[1] = gtk.TreeViewColumn('0-1000000')
win.tv.column[2] = gtk.TreeViewColumn('-10000-10000')
#Set up cell renderers
win.tv.cell = [None] * 3
for i in range(3):
win.tv.cell[i] = gtk.CellRendererText()
win.tv.cell[i].set_property('cell-background', 'cyan')
win.tv.append_column(win.tv.column[i])
win.tv.column[i].set_sort_column_id(i)
win.tv.column[i].pack_start(win.tv.cell[i], True)
#win.tv.column[i].set_attributes(win.tv.cell[i], text=i)
win.tv.column[i].set_attributes(win.tv.cell[i], text=i,
cell_background_set=3)
#Allow multiple selection
treeselection = win.tv.get_selection()
treeselection.set_mode(gtk.SELECTION_MULTIPLE)
##### End function tree view
win.show_all()
def main():
TreeViewTest()
gtk.main()
if __name__ == "__main__":
main()
Note that this is NOT a good way to make a GUI. You should be creating a proper class, not adding everything as an attribute to win. Please see the PyGTK 2.0 Tutorial for plenty of code examples.
Edit
Ok. Sorry about my earlier confusion over what your problem is. At least we've now got a nice simple example of a PyGTK program that creates a TreeView. :)
Anyway, it turns out that I was right when I guessed that the blue color of the selection turning to grey when the window loses focus on your computer is due to the behaviour of the window manager. I suppose there may be a way to block that in the application, by playing with Widget attributes, but I'm not sure how to do that. And besides, it's considered rude for programs to ignore the settings in the users' window theme.
So the most appropriate solution to your problem is to make the appropriate change in your window manager's appearance settings.
In KDE the relevant property is called "Inactive selection changes color", as described in Color Scheme Options:
Inactive selection changes color — If checked, the current selection in elements which do not have input focus will be drawn using a different color. This can assist visual identification of the element with input focus in some applications, especially those which simultaneously display several lists.
To change this, open up system settings (ALT+F2 → "systemsettings", or the [K] menu → system settings), then go to "Application appearance" and select "Colors". In the "Options" tab, uncheck the "Inactive selection changes color" setting, and click apply.
... ... ...
If you're not using KDE you'll have to figure out for yourself how to change it; hopefully, other window manager settings interfaces and documentation refer to this property with the same name or a similar name.

PyQt4: Auto completion in Qscintilla and horizontal scrolling

I want to show all attributes and tags in auto completion list of a html file if auto completion threshold is set to 1. I have tried this code to use APIs i set this code after the file is loaded in new mdi child(sub window) but it is not working:
lexer=Qsci.QsciLexerHTML()
api = Qsci.QsciAPIs(lexer)
## Add autocompletion strings
api.add("aLongString")
api.add("aLongerString")
api.add("aDifferentString")
api.add("sOmethingElse")
## Compile the api for use in the lexer
api.prepare()
self.activeMdiChild().setAutoCompletionSource(Qsci.QsciScintilla.AcsAPIs)
self.activeMdiChild().setLexer(lexer)
and my horizontal scroll bar is visible all the time i want to set it as scrollbarasneeded. please tell how to do these two tasks.
Other than failing to set the auto-completion threshold, there doesn't seem to be anything wrong with your example code. Here's a minimal working example:
from PyQt4 import QtGui, Qsci
class Window(Qsci.QsciScintilla):
def __init__(self):
Qsci.QsciScintilla.__init__(self)
lexer = Qsci.QsciLexerHTML(self)
api = Qsci.QsciAPIs(lexer)
api.add('aLongString')
api.add('aLongerString')
api.add('aDifferentString')
api.add('sOmethingElse')
api.prepare()
self.setAutoCompletionThreshold(1)
self.setAutoCompletionSource(Qsci.QsciScintilla.AcsAPIs)
self.setLexer(lexer)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
app.exec_()
The scrollbar-as-needed feature cannot really be solved, unless you are willing to reimplement everything yourself (which would not be easy). The underlying Scintilla control doesn't directly support automatic horizontal scrollbar hiding, because it involves a potentially very expensive calculation (i.e. determining the longest line). Most people who use Scintilla/Qscintilla just learn to put up with the ever-present horizontal scrollbar.

QApplication' is not defined

I downloaded the script below from http://www.pythoncentral.io/pyside-pyqt-tutorial-interactive-widgets-and-layout-containers/
I get the following error message: NameError: name 'QApplication' is not defined
I added the first two lines of the script.
That did not help.
I thought maybe I must not have qt installed. But when I tried to run PyQt4-4.10.3-gpl-Py2.7-Qt4.8.5-x32.exe, the program told me it was already installed.
Does anyone have any suggestions?
marc
# copied from http://www.pythoncentral.io/pyside-pyqt-tutorial-interactive-widgets-and-layout-containers/
# Every Qt application must have one and only one QApplication object;
# it receives the command line arguments passed to the script, as they
# can be used to customize the application's appearance and behavior
import sys
from PyQt4 import QtGui, QtCore
#import PyQt4.QtGui, PyQt4.QtCore
qt_app = QApplication(sys.argv)
class AbsolutePositioningExample(QWidget):
''' An example of PySide absolute positioning; the main window
inherits from QWidget, a convenient widget for an empty window. '''
def __init__(self):
# Initialize the object as a QWidget
QWidget.__init__(self)
# We have to set the size of the main window
# ourselves, since we control the entire layout
self.setMinimumSize(400, 185)
self.setWindowTitle('Dynamic Greeter')
# Create the controls with this object as their parent and set
# their position individually; each row is a label followed by
# another control
# Label for the salutation chooser
self.salutation_lbl = QLabel('Salutation:', self)
self.salutation_lbl.move(5, 5) # offset the first control 5px
# from top and left
self.salutations = ['Ahoy',
'Good day',
'Hello',
'Heyo',
'Hi',
'Salutations',
'Wassup',
'Yo']
# Create and fill the combo box to choose the salutation
self.salutation = QComboBox(self)
self.salutation.addItems(self.salutations)
# Allow 100px for the label and 5px each for borders at the
# far left, between the label and the combobox, and at the far
# right
self.salutation.setMinimumWidth(285)
# Place it five pixels to the right of the end of the label
self.salutation.move(110, 5)
# The label for the recipient control
self.recipient_lbl = QLabel('Recipient:', self)
# 5 pixel indent, 25 pixels lower than last pair of widgets
self.recipient_lbl.move(5, 30)
# The recipient control is an entry textbox
self.recipient = QLineEdit(self)
# Add some ghost text to indicate what sort of thing to enter
self.recipient.setPlaceholderText(""e.g. 'world' or 'Matey'"")
# Same width as the salutation
self.recipient.setMinimumWidth(285)
# Same indent as salutation but 25 pixels lower
self.recipient.move(110, 30)
# The label for the greeting widget
self.greeting_lbl = QLabel('Greeting:', self)
# Same indent as the others, but 45 pixels lower so it has
# physical separation, indicating difference of function
self.greeting_lbl.move(5, 75)
# The greeting widget is also a label
self.greeting = QLabel('', self)
# Same indent as the other controls
self.greeting.move(110, 75)
# The build button is a push button
self.build_button = QPushButton('&Build Greeting', self)
# Place it at the bottom right, narrower than
# the other interactive widgets
self.build_button.setMinimumWidth(145)
self.build_button.move(250, 150)
def run(self):
# Show the form
self.show()
# Run the Qt application
qt_app.exec_()
# Create an instance of the application window and run it
app = AbsolutePositioningExample()
app.run()
If you read through the tutorial in order, you'd see that the previous article in the series showed the stuff you need to part at the start of each fragment to make it a runnable program. The author apparently did this so that the same code could be used with both PyQt and PySide.
So, if you're using PyQt4, you'll need to add this:
# Allow access to command-line arguments
import sys
# SIP allows us to select the API we wish to use
import sip
# use the more modern PyQt API (not enabled by default in Python 2.x);
# must precede importing any module that provides the API specified
sip.setapi('QDate', 2)
sip.setapi('QDateTime', 2)
sip.setapi('QString', 2)
sip.setapi('QTextStream', 2)
sip.setapi('QTime', 2)
sip.setapi('QUrl', 2)
sip.setapi('QVariant', 2)
# Import all of Qt
from PyQt4.Qt import *
If PySide:
# Allow access to command-line arguments
import sys
# Import the core and GUI elements of Qt
from PySide.QtCore import *
from PySide.QtGui import *
Below the box showing your this boilerplate, there's a nice, readable explanation of what it all means and why you need to do it.
However, I'd suggest that if you're trying to learn from a tutorial, you start at the start and work forward, instead of starting in the middle and trying to figure out what you missed along the way.
If you just do from PyQt4 import QtGui, QtCore instead of importing * from them, the names in those modules are available, but only as qualified names. That is, instead of QApplication, you have to write QtCore.QApplication.
If you don't understand the difference, read Modules in the official Python tutorial, or something equivalent, to learn how imports work.
I guess that import is wrong, it should be:
from PyQt4.QtCore import *
from PyQt4.QtGui import *
For anyone experiencing this issue in PyQt5, try using QCoreApplication instead and it should work.

Categories