Versión: 2.7
Este código de fuente puede utilizarse con varios objetivos. Trata de una consola gráfica de Python, similar a la integrada con IDLE, que hace uso del módulo code para ejecutar el código, PyQt para el diseño de la interfaz gráfica junto con QScintilla, una portación del control para edición de código Scintilla. A través del syntax highlighting pretende proveer una simple consola de mayor comodidad en comparación a la que se distribuye junto con CPython. Podrá ser de utilidad para aquellos usuarios que deseen explorar código en acción de PyQt, el control QScintilla y el módulo estándar code.
A lo largo del código podrán observar los múltiples comentarios que espero que les sean de utilidad para su comprensión.
El código requiere la instalación del paquete PyQt 4 y la versión de Python 2.7. Para aquellos usuarios de Windows que quieran ejecutar el script sin los requerimientos anteriores pueden descargar el archivo ejecutable desde aquí.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# main.py
#
# Copyright 2013 Recursos Python - www.recursospython.com
#
import sys
from code import InteractiveConsole
from threading import Thread
from time import sleep
from PyQt4.QtCore import QObject, QRect, Qt, pyqtSignal
from PyQt4.QtGui import QApplication, QMainWindow
from PyQt4.Qsci import QsciScintilla, QsciLexerPython
class GUIConsole(Thread, InteractiveConsole):
def __init__(self, scintilla):
Thread.__init__(self)
InteractiveConsole.__init__(self)
self.scintilla = scintilla
def write(self, string):
"""
Enviar el output al editor en lugar de
la consola.
"""
self.scintilla.append(string)
def raw_input(self, prompt_unused):
"""
Leer la entrada desde el editor en lugar
de la consola.
"""
self.scintilla.append(">>> ") # Ignorar el argumento
self.scintilla.SendScintilla(
self.scintilla.SCI_GOTOPOS, len(self.scintilla.text())
)
return self.scintilla.get_input()
def run(self):
try:
self.interact()
except AttributeError:
# Usamos AttributeError para terminar el thread
pass
class SyntaxHighliter(QsciScintilla):
"""
Heredamos de QsciScintilla para detectar la
presión de teclas y retornar la línea actual.
"""
def __init__(self, parent):
QsciScintilla.__init__(self, parent)
self._output_data = None
self._run = True
def keyPressEvent(self, event):
# Tecla presionada
key = event.key()
# Posición actual
current_pos = self.SendScintilla(self.SCI_GETCURRENTPOS)
# Tamaño del contenido
length = len(self.text())
# Contenido de la última línea
last_line_content = self.text(
self.SendScintilla(self.SCI_LINEFROMPOSITION, length)
)
# Las teclas arriba, abajo, derecha e izquierda están permitidas
if not (key == Qt.Key_Up or key == Qt.Key_Down or
key == Qt.Key_Left or key == Qt.Key_Right):
# Chequear que se pueda escribir en la posición actual
if (length - current_pos - len(last_line_content)) >= 0:
return
# Tecla enter (más la del teclado numérico)
if key == Qt.Key_Enter or key == Qt.Key_Return:
# Contenido de la línea actual
self._output_data = self.text(
self.SendScintilla(self.SCI_LINEFROMPOSITION, length)
)
# Llamar a la función original
QsciScintilla.keyPressEvent(self, event)
def get_input(self):
# Esperar hasta que se llene el búfer
while self._output_data is None:
if not self._run:
# Lanzar AttributeError
return
sleep(0.01)
# Remueve el banner ">>> " y convierte los datos
output = unicode(self._output_data[4:])
# Resetear el búfer
self._output_data = None
return output
def stop(self):
self._run = False
class Window(QMainWindow):
def __init__(self):
# Inicializar la clase padre
QMainWindow.__init__(self)
# Tamaño y título
self.resize(500, 300)
self.setWindowTitle("Consola Recursos Python")
# Editor - resaltador de sintaxis
self.scintilla = SyntaxHighliter(self)
self.scintilla.setGeometry(QRect(10, 10, 480, 250))
self.scintilla.setLexer(QsciLexerPython())
# Ejecutar la consola en un nuevo hilo
self.console = GUIConsole(self.scintilla)
self.console.start()
# Ajustar el editor a la ventana
self.setCentralWidget(self.scintilla)
# Cambiar el output
self.original_stdout = sys.stdout
sys.stdout = self
def write(self, string):
self.console.write(string)
def closeEvent(self, event):
"""Terminar el thread y establecer el stdout original"""
sys.stdout = self.original_stdout
self.scintilla.stop()
QMainWindow.closeEvent(self, event)
if __name__ == "__main__":
app = QApplication([])
window = Window()
window.show()
app.exec_()
Curso online 👨💻
¡Ya lanzamos el curso oficial de Recursos Python en Udemy!
Un curso moderno para aprender Python desde cero con programación orientada a objetos, SQL y tkinter en 2024.
Consultoría 💡
Ofrecemos servicios profesionales de desarrollo y capacitación en Python a personas y empresas. Consultanos por tu proyecto.
