wxPython dialogs: How to validate inputs in multiple controls? - validation

I have a wx.Dialog with several input fields. When the OK button is pressed I want to run validations such as:
If one of three fields is filled in, all three must be filled in.
If a radiobutton is set, then it's corresponding field must not be empty.
I know about the normal validators that get attached to a control with wx.Window.SetValidator(). But these just validate the content of their respective control.
I tried attaching a validator to the wx.Dialog, but this is not called unfortunately.
I tried binding the event from the ID_OK button to a handler to do the validation there, but the result is that the dialog doesn't close anymore.
What is the proper way to do this kind of validation?
Below is my code with what I tried:
import wx
class DialogValidator(wx.Validator):
def Clone(self):
return DialogValidator()
def Validate(self, win):
print("this method is never called :-(")
field1 = win.field1.GetValue()
field2 = win.field2.GetValue()
field3 = win.field3.GetValue()
if len(field1) > 0 or len(field2) > 0 or len(field3) > 0:
# if one of these is filled in, all three must
if len(field1) == 0 or len(field2) == 0 or len(field3) == 0:
wx.MessageBox("All three fields must be filled in!", "Error")
return False
return True
def TransferToWindow(self):
return True
def TransferFromWindow(self):
return True
class MyDialog(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
self.field1 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field2 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field3 = wx.TextCtrl(self, wx.ID_ANY, "")
self.radio1 = wx.RadioButton(self, wx.ID_ANY, "radio1", style=wx.RB_GROUP)
self.radio2 = wx.RadioButton(self, wx.ID_ANY, "radio2")
self.dialog_btn_sizer = wx.StdDialogButtonSizer()
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_OK))
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_CANCEL))
self.dialog_btn_sizer.Realize()
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.radio1)
main_sizer.Add(self.radio2)
main_sizer.Add(self.field1)
main_sizer.Add(self.field2)
main_sizer.Add(self.field3)
main_sizer.Add(self.dialog_btn_sizer, 0, wx.EXPAND, 0)
self.SetSizer(main_sizer)
main_sizer.Fit(self)
self.Layout()
self.SetValidator(DialogValidator()) # doesn't work unfortunately
self.Bind(wx.EVT_BUTTON, self.on_ok, id=wx.ID_OK) # doesn't work either
def on_ok(self, event):
field1 = self.field1.GetValue()
field2 = self.field2.GetValue()
field3 = self.field3.GetValue()
if len(field1) > 0 or len(field2) > 0 or len(field3) > 0:
# if one of these is filled in, all three must
if len(field1) == 0 or len(field2) == 0 or len(field3) == 0:
wx.MessageBox("All three fields must be filled in!", "Error")
event.Skip()
return
# Note that I do NOT call event.Skip() here!
# I was hoping the original handler would pick up the event
# and properly close the dialog -> unfortunately this is not the case
print("inputs fine, now the dialog should get closed")

I now solved it by setting a validator on one field that accesses the other fields by going over the dialog. I found out that win in wx.Validator.Validate(self, win) refers to the underlying wx.Dialog.
(Why handling the ID_OK button didn't work I don't know, but this would be another question.)
I'm posting my solution in the hope it helps others struggling with validators:
import wx
class FieldValidator(wx.Validator):
def Clone(self):
return FieldValidator()
def Validate(self, win):
# 'win' refers to the dialog,
# so I can access the other controls like this:
field1 = win.field1.GetValue()
field2 = win.field2.GetValue()
field3 = win.field3.GetValue()
# btw: with self.GetWindow() I can get the control being validated
if len(field1) > 0 or len(field2) > 0 or len(field3) > 0:
# if one of these is filled in, all three must
if len(field1) == 0 or len(field2) == 0 or len(field3) == 0:
wx.MessageBox("All three fields must be filled in!", "Error")
return False
return True
def TransferToWindow(self):
return True
def TransferFromWindow(self):
return True
class MyDialog(wx.Dialog):
def __init__(self, *args, **kwds):
wx.Dialog.__init__(self, *args, **kwds)
self.field1 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field2 = wx.TextCtrl(self, wx.ID_ANY, "")
self.field3 = wx.TextCtrl(self, wx.ID_ANY, "")
self.radio1 = wx.RadioButton(self, wx.ID_ANY, "radio1", style=wx.RB_GROUP)
self.radio2 = wx.RadioButton(self, wx.ID_ANY, "radio2")
self.dialog_btn_sizer = wx.StdDialogButtonSizer()
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_OK))
self.dialog_btn_sizer.AddButton(wx.Button(self, wx.ID_CANCEL))
self.dialog_btn_sizer.Realize()
main_sizer = wx.BoxSizer(wx.VERTICAL)
main_sizer.Add(self.radio1)
main_sizer.Add(self.radio2)
main_sizer.Add(self.field1)
main_sizer.Add(self.field2)
main_sizer.Add(self.field3)
main_sizer.Add(self.dialog_btn_sizer, 0, wx.EXPAND, 0)
self.SetSizer(main_sizer)
main_sizer.Fit(self)
self.Layout()
self.field1.SetValidator(FieldValidator())

Related

Ruby instance attribute somehow being set to `true` instead of the intended value upon another attributes modification

Learning oop in Ruby and encountering some unexpected behavior in a class i've written. Here is my Radio class, I can change the volume attribute, but when I change the freq attribute, the band attribute is changed from fm to true. I cannot figure out why this is happening.
my file init.rb that's calling the Radio class:
require_relative 'classes/radio'
fm_radio = Radio.fm
fm_radio.volume = 10
puts fm_radio.status
#volume: 10 band: fm frequency: 88.0
fm_radio.freq = 99.0
puts fm_radio.status
#volume: 10 band: true frequency: 99.0
puts fm_radio.band
# true
my file radio.rb that contains the Radio class:
class Radio
attr_accessor :volume, :freq
attr_reader :band
def initialize(band)
#band = band
if band == 'am'
#freq = 540.0
else
#freq = 88.0
end
#volume = 1
end
def volume=(value)
return if value < 1 || value > 10
#volume = value
end
def freq=(value)
if #band = 'am' && (540.0..1600).include?(value)
#freq = value
elsif #band = 'fm' && (88.0..108.0).include?(value)
#freq = value
else
puts 'out of range'
end
end
def crank_it_up
#volume = 11
end
def status
"volume: #{#volume} band: #{#band} frequency: #{#freq}"
end
def self.am
Radio.new('am')
end
def self.fm
Radio.new('fm')
end
end
Your error is in these two lines:
if #band = 'am' && (540.0..1600).include?(value)
elsif #band = 'fm' && (88.0..108.0).include?(value)
Using a single =, you're assigning to #band what is evaluated from 'am' && (540.0..1600).include?(value), which eventually will be a boolean value.
You must use == to compare #band with another string.

sqlany-django : Error - 'django.db.backends.utils' has no attribute 'typecast_decimal'

When I am running server in django, getting this error:
File "D:\API\createapi\lib\site-packages\sqlany_django\base.py", line 48, in Database.register_converter(Database.DT_DECIMAL, util.typecast_decimal)
AttributeError: module 'django.db.backends.utils' has no attribute typecast_decimal'.
Found some threads regarding this but was not able to find a solution.
Kindly advise on how to proceed! Thanks in advance.
Base.py
"""
SQL Anywhere database backend for Django.
Requires sqlanydb
"""
import re,ctypes,sys
try:
import sqlanydb as Database
except ImportError as e:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured("Error loading sqlanydb module: %s" % e)
from django import VERSION as djangoVersion
if djangoVersion[:2] >= (1, 4):
from django.utils.timezone import is_aware, is_naive, utc, make_naive, make_aware, get_default_timezone
import datetime
from django.conf import settings
if djangoVersion[:2] >= (1, 8):
from django.db.backends.base.features import BaseDatabaseFeatures
from django.db.backends.base.operations import BaseDatabaseOperations
from django.db.backends.base.base import BaseDatabaseWrapper
from django.db.backends import utils as util
else:
from django.db.backends import *
if djangoVersion[:2] >= (1, 7):
# renamed in 1.7
util = utils
from django.db.backends.signals import connection_created
from sqlany_django.client import DatabaseClient
from sqlany_django.creation import DatabaseCreation
from sqlany_django.introspection import DatabaseIntrospection
from sqlany_django.validation import DatabaseValidation
if djangoVersion[:2] >= (1, 7):
from sqlany_django.schema import DatabaseSchemaEditor
if djangoVersion[:2] >= (1, 8):
from sqlany_django.creation import global_data_types
DatabaseError = Database.DatabaseError
IntegrityError = Database.IntegrityError
Database.register_converter(Database.DT_TIMESTAMP, util.typecast_timestamp)
Database.register_converter(Database.DT_DATE, util.typecast_date)
Database.register_converter(Database.DT_TIME, util.typecast_time)
Database.register_converter(Database.DT_DECIMAL, util.typecast_decimal)
Database.register_converter(Database.DT_BIT, lambda x: x if x is None else bool(x))
def trace(x):
# print( x )
return x
def _datetimes_in(args):
def fix(arg):
if isinstance(arg, datetime.datetime):
if is_naive(arg):
warnings.warn("Received a naive datetime (%s) while timezone support is active." % arg, RuntimeWarning)
arg = make_aware(arg, timezone.get_default_timezone())
arg = arg.astimezone(utc).replace(tzinfo=None)
return arg
return tuple(fix(arg) for arg in args)
class CursorWrapper(object):
"""
A thin wrapper around sqlanydb's normal cursor class so that we can catch
particular exception instances and reraise them with the right types.
Implemented as a wrapper, rather than a subclass, so that we aren't stuck
to the particular underlying representation returned by Connection.cursor().
"""
codes_for_integrityerror = (1048,)
def __init__(self, cursor):
self.cursor = cursor
def __del__(self):
if self.cursor:
self.cursor.close()
self.cursor = None
def convert_query(self, query, num_params):
"""
Django uses "format" style placeholders, but SQL Anywhere uses "qmark" style.
This fixes it -- but note that if you want to use a literal "%s" in a query,
you'll need to use "%%s".
"""
return query if num_params == 0 else query % tuple("?" * num_params)
def execute(self, query, args=()):
if djangoVersion[:2] >= (1, 4) and settings.USE_TZ:
args = _datetimes_in(args)
try:
if args != None:
query = self.convert_query(query, len(args))
ret = self.cursor.execute(trace(query), trace(args))
return ret
except Database.OperationalError as e:
if e.message == 'Connection was terminated':
from django import db
try:
db.close_old_connections()
except AttributeError:
db.close_connection()
# Map some error codes to IntegrityError, since they seem to be
# misclassified and Django would prefer the more logical place.
if e.errorcode in self.codes_for_integrityerror:
raise Database.IntegrityError(e)
raise
def executemany(self, query, args):
if djangoVersion[:2] >= (1, 4) and settings.USE_TZ:
args = tuple(_datetimes_in(arg) for arg in args)
try:
try:
len(args)
except TypeError:
args = tuple(args)
if len(args) > 0:
query = self.convert_query(query, len(args[0]))
ret = self.cursor.executemany(trace(query), trace(args))
return trace(ret)
else:
return None
except Database.OperationalError as e:
# Map some error codes to IntegrityError, since they seem to be
# misclassified and Django would prefer the more logical place.
if e.errorcode in self.codes_for_integrityerror:
raise Database.IntegrityError(e)
raise
def fetchone(self):
if djangoVersion[:2] < (1, 4) or not settings.USE_TZ:
return trace(self.cursor.fetchone())
return self._datetimes_out(self.cursor.fetchone())
def fetchmany(self, size=0):
if djangoVersion[:2] < (1, 4) or not settings.USE_TZ:
return trace(self.cursor.fetchmany(size))
rows = self.cursor.fetchmany(size)
return list(self._datetimes_out(row) for row in rows)
def fetchall(self):
if djangoVersion[:2] < (1, 4) or not settings.USE_TZ:
return trace(self.cursor.fetchall())
return list(self._datetimes_out(row) for row in self.cursor.fetchall())
def _datetimes_out(self, row):
def fix(item):
value, desc = item
if desc[1] == Database.DATETIME:
if value is not None and is_naive(value):
value = value.replace(tzinfo=utc)
return value
if row is None:
return row
return trace(tuple(fix(item) for item in zip(row, self.cursor.description)))
def __getattr__(self, attr):
if attr in self.__dict__:
return self.__dict__[attr]
else:
return getattr(self.cursor, attr)
def __iter__(self):
return iter(self.fetchall())
class DatabaseFeatures(BaseDatabaseFeatures):
allows_group_by_pk = False
empty_fetchmany_value = []
has_bulk_insert = True
has_select_for_update = True
has_zoneinfo_database = False
related_fields_match_type = True
supports_regex_backreferencing = False
supports_sequence_reset = False
update_can_self_select = False
uses_custom_query_class = False
class DatabaseOperations(BaseDatabaseOperations):
compiler_module = "sqlany_django.compiler"
def bulk_insert_sql(self, fields, num_values):
items_sql = "(%s)" % ", ".join(["%s"] * len(fields))
return "VALUES " + ", ".join([items_sql] * num_values)
def date_extract_sql(self, lookup_type, field_name):
"""
Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
extracts a value from the given date field field_name.
"""
if lookup_type == 'week_day':
# Returns an integer, 1-7, Sunday=1
return "DATEFORMAT(%s, 'd')" % field_name
else:
# YEAR(), MONTH(), DAY() functions
return "%s(%s)" % (lookup_type.upper(), field_name)
if djangoVersion[:2] >= (1, 8):
# SQL Anywhere does not support the INTERVAL syntax
pass
#def date_interval_sql(self, timedelta):
else:
def date_interval_sql(self, sql, connector, timedelta):
"""
Implements the date interval functionality for expressions
"""
return 'DATEADD(day, %s(%d), DATEADD(second, %s(%d), DATEADD(microsecond, %s(%d), %s)))' % (connector, timedelta.days, connector, timedelta.seconds, connector, timedelta.microseconds, sql)
def date_trunc_sql(self, lookup_type, field_name):
"""
Given a lookup_type of 'year', 'month' or 'day', returns the SQL that
truncates the given date field field_name to a DATE object with only
the given specificity.
"""
fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
format = ('YYYY-', 'MM', '-DD', 'HH:', 'NN', ':SS') # Use double percents to escape.
format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
try:
i = fields.index(lookup_type) + 1
except ValueError:
sql = field_name
else:
format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
sql = "CAST(DATEFORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
return sql
def datetime_extract_sql(self, lookup_type, field_name, tzname):
"""
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
'second', returns the SQL that extracts a value from the given
datetime field field_name, and a tuple of parameters.
"""
if lookup_type == 'week_day':
# Returns an integer, 1-7, Sunday=1
sql = "DATEFORMAT(%s, 'd')" % field_name
else:
# YEAR(), MONTH(), DAY(), HOUR(), MINUTE(), SECOND() functions
sql = "%s(%s)" % (lookup_type.upper(), field_name)
return sql,[]
def datetime_trunc_sql(self, lookup_type, field_name, tzname):
"""
Given a lookup_type of 'year', 'month', 'day', 'hour', 'minute' or
'second', returns the SQL that truncates the given datetime field
field_name to a datetime object with only the given specificity, and
a tuple of parameters.
"""
fields = ['year', 'month', 'day', 'hour', 'minute', 'second']
format = ('YYYY-', 'MM', '-DD', 'HH:', 'NN', ':SS') # Use double percents to escape.
format_def = ('0000-', '01', '-01', ' 00:', '00', ':00')
try:
i = fields.index(lookup_type) + 1
except ValueError:
sql = field_name
else:
format_str = ''.join([f for f in format[:i]] + [f for f in format_def[i:]])
sql = "CAST(DATEFORMAT(%s, '%s') AS DATETIME)" % (field_name, format_str)
return sql,[]
def deferrable_sql(self):
return ""
def drop_foreignkey_sql(self):
"""
Returns the SQL command that drops a foreign key.
"""
# This will work provided it is inserted in an ALTER TABLE statement
return "DROP FOREIGN KEY"
def force_no_ordering(self):
"""
"ORDER BY NULL" prevents SQL Anywhere from implicitly ordering by grouped
columns. If no ordering would otherwise be applied, we don't want any
implicit sorting going on.
"""
return ["NULL"]
def fulltext_search_sql(self, field_name):
"""
Returns the SQL WHERE clause to use in order to perform a full-text
search of the given field_name. Note that the resulting string should
contain a '%s' placeholder for the value being searched against.
"""
return 'CONTAINS(%s, %%s)' % field_name
def last_insert_id(self, cursor, table_name, pk_name):
cursor.execute('SELECT ##identity')
return cursor.fetchone()[0]
def max_name_length(self):
"""
Returns the maximum length of table and column names, or None if there
is no limit.
"""
# SQL Anywhere 11 has a maximum of 128 for table and column names
return 128
def no_limit_value(self):
"""
Returns the value to use for the LIMIT when we are wanting "LIMIT
infinity". Returns None if the limit clause can be omitted in this case.
"""
return None
def prep_for_iexact_query(self, x):
return x
def query_class(self, DefaultQueryClass):
"""
Given the default Query class, returns a custom Query class
to use for this backend. Returns None if a custom Query isn't used.
See also BaseDatabaseFeatures.uses_custom_query_class, which regulates
whether this method is called at all.
"""
return query.query_class(DefaultQueryClass)
def quote_name(self, name):
"""
Returns a quoted version of the given table, index or column name. Does
not quote the given name if it's already been quoted.
"""
if name.startswith('"') and name.endswith('"'):
return name # Quoting once is enough.
return '"%s"' % name
def regex_lookup(self, lookup_type):
"""
Returns the string to use in a query when performing regular expression
lookups (using "regex" or "iregex"). The resulting string should
contain a '%s' placeholder for the column being searched against.
"""
if lookup_type == 'iregex':
raise NotImplementedError("SQL Anywhere does not support case insensitive regular expressions")
return "%s REGEXP ('.*'||%s||'.*')"
def random_function_sql(self):
"""
Returns a SQL expression that returns a random value.
"""
return 'RAND()'
def savepoint_create_sql(self, sid):
"""
Returns the SQL for starting a new savepoint. Only required if the
"uses_savepoints" feature is True. The "sid" parameter is a string
for the savepoint id.
"""
return 'SAVEPOINT ' + self.quote_name(sid)
def savepoint_commit_sql(self, sid):
"""
Returns the SQL for committing the given savepoint.
"""
return 'COMMIT'
def savepoint_rollback_sql(self, sid):
"""
Returns the SQL for rolling back the given savepoint.
"""
return 'ROLLBACK TO SAVEPOINT ' + self.quote_name(sid)
def sql_flush(self, style, tables, sequences):
"""
Returns a list of SQL statements required to remove all data from
the given database tables (without actually removing the tables
themselves).
"""
if tables:
sql = ['SET TEMPORARY OPTION wait_for_commit = \'On\';']
# TODO: We should truncate tables here, but there may cause an error;
# for now, delete (all) from each table
for table in tables:
sql.append('DELETE FROM %s;' % self.quote_name(table))
# TODO: This requires DBA authority, but once the truncate bug is fixed
# it won't be necessary
for sequence in sequences:
sql.append('call sa_reset_identity(\'%s\', NULL, 0);' % sequence['table'])
sql.append('SET TEMPORARY OPTION wait_for_commit = \'Off\';')
sql.append('COMMIT;')
return sql
def value_to_db_datetime(self, value):
if value is None:
return None
if djangoVersion[:2] <= (1, 3):
# SQL Anywhere doesn't support tz-aware datetimes
if value.tzinfo is not None:
raise ValueError("SQL Anywhere backend does not support timezone-aware datetimes.")
else:
if is_aware(value):
if settings.USE_TZ:
value = value.astimezone(utc).replace(tzinfo=None)
else:
make_naive(value, get_default_timezone())
return str(value)
def value_to_db_time(self, value):
if value is None:
return None
if djangoVersion[:2] <= (1, 3):
# SQL Anywhere doesn't support tz-aware datetimes
if value.tzinfo is not None:
raise ValueError("SQL Anywhere backend does not support timezone-aware datetimes.")
else:
if is_aware(value):
make_naive(value, get_default_timezone())
return str(value)
class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'sqlanywhere'
operators = {
'exact': '= %s',
'iexact': '= %s',
'contains': "LIKE %s ESCAPE '\\'",
'icontains': "LIKE %s ESCAPE '\\'",
'regex': "REGEXP ('.*'||%s||'.*')",
# 'iregex': "REGEXP ('.*'||%s||'.*')",
'gt': '> %s',
'gte': '>= %s',
'lt': '< %s',
'lte': '<= %s',
'startswith': "LIKE %s ESCAPE '\\'",
'istartswith': "LIKE %s ESCAPE '\\'",
'endswith': "LIKE %s ESCAPE '\\'",
'iendswith': "LIKE %s ESCAPE '\\'"
}
if djangoVersion[:2] >= (1, 8):
# Moved from DatabaseCreation in 1.8
data_types = global_data_types
Database = Database
def __init__(self, *args, **kwargs):
super(DatabaseWrapper, self).__init__(*args, **kwargs)
self.server_version = None
if djangoVersion[:2] >= (1, 3):
self.features = DatabaseFeatures(self)
else:
self.features = DatabaseFeatures()
if djangoVersion[:2] >= (1, 4):
self.ops = DatabaseOperations(self)
else:
self.ops = DatabaseOperations()
self.client = DatabaseClient(self)
self.creation = DatabaseCreation(self)
self.introspection = DatabaseIntrospection(self)
if djangoVersion[:2] >= (1, 2):
self.validation = DatabaseValidation(self)
else:
self.validation = DatabaseValidation()
def _valid_connection(self):
if self.connection is not None:
try:
self.connection.con()
return True
except InterfaceError:
self.connection.close()
self.connection = None
return False
def check_constraints(self, table_names=None):
self.cursor().execute('PREPARE TO COMMIT')
def _cursor(self):
return self.create_cursor()
def _rollback(self):
try:
BaseDatabaseWrapper._rollback(self)
except Database.NotSupportedError:
pass
# New methods for Django 1.6
def get_connection_params(self):
kwargs = {}
links = {}
settings_dict = self.settings_dict
def setting( key ):
if key in settings_dict:
return settings_dict[key]
dbkey = 'DATABASE_%s' % key
if dbkey in settings_dict:
return settings_dict[dbkey]
return None
#
def empty( s ):
return True if ( s is None or s == '' ) else False
#
uid = setting( 'USER' )
if not empty( uid ):
kwargs['uid'] = uid
dbn = setting( 'NAME' )
if not empty( dbn ):
kwargs['dbn'] = dbn
pwd = setting( 'PASSWORD' )
if not empty( pwd ):
kwargs['pwd'] = pwd
root = Database.Root('PYTHON')
try:
vers = root.api.sqlany_client_version()
ret = True
except:
length = 1000
buffer = ctypes.create_string_buffer(length)
ret = root.api.sqlany_client_version(ctypes.byref(buffer), length)
vers = buffer.value
if ret:
if sys.version_info[0] >= 3:
# Python 3: convert bytes to str
vers = str(vers, 'utf-8')
vers = int(vers.split('.')[0])
else:
vers = 11 # assume old
host = setting( 'HOST' )
if host == '':
host = 'localhost' # "Set to empty string for localhost"
if not empty( host ) and vers > 11:
kwargs['host'] = host
port = setting( 'PORT' )
if not empty( port ):
kwargs['host'] += ':%s' % port
else:
if not empty( host ):
links['host'] = host
port = setting( 'PORT' )
if not empty( port ):
links['port'] = str( port )
if len(links) > 0:
kwargs['links'] = 'tcpip(' + ','.join(k+'='+v for k, v in list(links.items())) + ')'
kwargs.update(setting( 'OPTIONS' ))
return kwargs
def get_new_connection( self, conn_params ):
conn = Database.connect(**conn_params)
if conn is not None and djangoVersion[:2] >= (1, 6):
# Autocommit is the default for 1.6+
curs = conn.cursor()
curs.execute( "SET TEMPORARY OPTION chained='Off'" )
curs.close()
return conn
def init_connection_state( self ):
if 'AUTOCOMMIT' in self.settings_dict and \
not self.settings_dict['AUTOCOMMIT']:
self.set_autocommit( False )
def create_cursor( self ):
cursor = None
if not self._valid_connection():
kwargs = self.get_connection_params()
self.connection = self.get_new_connection(kwargs)
cursor = CursorWrapper(self.connection.cursor())
if djangoVersion[:2] < (1, 2):
cursor.execute("SET TEMPORARY OPTION PUBLIC.reserved_keywords='LIMIT'")
cursor.execute("SET TEMPORARY OPTION TIMESTAMP_FORMAT='YYYY-MM-DD HH:NN:SS.SSSSSS'")
connection_created.send(sender=self.__class__, connection=self)
if not cursor:
cursor = CursorWrapper(self.connection.cursor())
return cursor
def _set_autocommit( self, autocommit ):
"""
Backend-specific implementation to enable or disable autocommit.
"""
curs = self.create_cursor()
curs.execute( "SET TEMPORARY OPTION chained='%s'" %
('Off' if autocommit else 'On') )
curs.close()
def is_usable(self):
"""
Tests if the database connection is usable.
This function may assume that self.connection is not None.
"""
return self._valid_connection()
# New methods for Django 1.7
if djangoVersion[:2] >= (1, 7):
def schema_editor(self, *args, **kwargs):
"Returns a new instance of this backend's SchemaEditor"
return DatabaseSchemaEditor( self, *args, **kwargs )

wxPython ImageViewer

I am to create a simple image viewer using wxPython. I am using a panel and a button upon which by clicking a picture would be shown from a directory (Images). Below is the code. I have taken pieces from different websites.
My question is if I maximize the window, the picture viewer as well as the button remain same. I want the picture viewer to increase as well.
Another thing is, after I press the "Load" button, it moves to the left. How do I fix these two problems?
I understand for those 2 above questions, this so big program might be unnecessary. I am a newbie to Python.
Thanks in advance.
import wx, os
class Panel1(wx.Panel):
def __init__(self, *args, **kwds):
wx.Panel.__init__(self, *args, **kwds)
self.jpgs = self.GetJpgList("./Images")
self.CurrentJpg = 0
self.MaxImageSize = 200
self.img = wx.EmptyImage(self.MaxImageSize,self.MaxImageSize)
self.imageCtrl = wx.StaticBitmap(self, wx.ID_ANY, wx.BitmapFromImage(self.img))
self.button_1 = wx.Button(self, wx.ID_ANY, "Load")
self.Bind(wx.EVT_BUTTON, self.OnLoad, self.button_1)
self.__do_layout()
self.Layout()
def GetJpgList(self, dir):
jpgs = [f for f in os.listdir(dir) if f[-4:] == ".JPG"]
return [os.path.join(dir, f) for f in jpgs]
def __do_layout(self):
sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
sizer_2 = wx.BoxSizer(wx.VERTICAL)
sizer_1.Add((1,1),1)
sizer_1.Add(self.imageCtrl, 0, wx.ALL|wx.EXPAND, 5)
sizer_1.Add((1,1),1)
sizer_1.Add(wx.StaticLine(self, wx.ID_ANY), 0, wx.ALL|wx.EXPAND, 5)
sizer_2.Add(self.button_1, 0, wx.ALL|wx.TOP, 5)
sizer_1.Add(sizer_2, 0, wx.ALL, 5)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
def OnNext(self, event):
path = self.jpgs[self.CurrentJpg]
self.Img = wx.Image(path, wx.BITMAP_TYPE_ANY)
W = self.Img.GetWidth()
H = self.Img.GetHeight()
if W > H:
NewW = self.MaxImageSize
NewH = self.MaxImageSize * H / W
else:
NewH = self.MaxImageSize
NewW = self.MaxImageSize * W / H
self.Img = self.Img.Scale(NewW,NewH)
self.imageCtrl.SetBitmap(wx.BitmapFromImage(self.Img))
#self.Fit()
#self.Layout()
self.Refresh()
self.CurrentJpg += 1
if self.CurrentJpg > len(self.jpgs) -1:
self.CurrentJpg = 0
# end of class Panel1
class Frame1(wx.Frame):
def __init__(self, *args, **kwds):
wx.Frame.__init__(self, *args, **kwds)
self.__set_properties()
self.__do_layout()
def __set_properties(self):
self.SetTitle("Picture")
def __do_layout(self):
panel1 = Panel1(self)
self.sizer = wx.BoxSizer(wx.VERTICAL)
self.sizer.Add(panel1, 1, wx.EXPAND)
self.SetSizer(self.sizer)
self.sizer.Fit(self)
self.Layout()
self.Centre()
# end of class Frame1
class Game1(wx.App):
def OnInit(self):
wx.InitAllImageHandlers()
frame1 = Frame1(None, wx.ID_ANY, "")
self.SetTopWindow(frame1)
frame1.Show()
return 1
# end of class Game1
if __name__ == "__main__":
game1 = Game1(0)
game1.MainLoop()
To make the image resize itself on maximize, you will need to catch wx.EVT_MAXIMIZE. Then in your event handler, you'll need to call your function that updates the image control you created. You may need to use the Frame's size to help you determine what your MaxImageSize should be.
For the load button issue, you may need to call the sizer or the widget's parent's Layout() method.

how to delegate on specific postion(row, col) in PyQt QTreeView

my purpose is to display an different icon in treeview list when a specific postion(row, column) match a value. eg: (row, 2) is dir or file, will diplay different icon. because this is not used in local filesystem, QDir or Qfilesystem model not suite for this.
i know a bit on MVC that controller display in view, make model as data interface api. but i do not how to make it works on specific position(row ,col) as my expect.
i have tried to add args in ImageDelegate(like pass icon file name to it), but failed maybe due to its parent Class not accept more args.
hope someone can give me some light.
class ImageDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent=None):
QtGui.QStyledItemDelegate.__init__(self, parent)
#self.icon =icon
def paint(self, painter, option, index):
#painter.fillRect(option.rect, QtGui.QColor(191,222,185))
# path = "path\to\my\image.jpg"
path = "icon1.png"
image = QtGui.QImage(str(path))
pixmap = QtGui.QPixmap.fromImage(image)
pixmap.scaled(16, 16, QtCore.Qt.KeepAspectRatio)
painter.drawPixmap(option.rect.x(), option.rect.y(), pixmap)
and i can use this delegate in my view. but it will change all line in specific column.
def init_remotetreeview(self):
self.model = myModel(self.remote_Treeview)
for therow in range(self.model.rowCount(QModelIndex())) :
print self.model.data(self.model.index(therow, 2, QtCore.QModelIndex()),Qt.DisplayRole).toString() # i do check the value will used to load correct icon.
self.remote_Treeview.setItemDelegate(ImageDelegate(self)) # this change all lines
self.remote_Treeview.setModel(self.model)
In fact, your have some light in your code, isn't it ? (Just kidding.)
Your have right way to use QtGui.QStyledItemDelegate. I have reference how to implement it (But, C++ only). 'Star Delegate Example', 'QItemDelegate Class Reference C++' and 'QItemDelegate Class Reference PyQt4';
Keyword : Your have to implement paint draw your element what your want (I think this is your want.)
Little example, Hope is help;
import sys
from PyQt4 import QtCore, QtGui
from functools import partial
class QCustomDelegate (QtGui.QItemDelegate):
signalNewPath = QtCore.pyqtSignal(object)
def createEditor (self, parentQWidget, optionQStyleOptionViewItem, indexQModelIndex):
column = indexQModelIndex.column()
if column == 0:
editorQWidget = QtGui.QPushButton(parentQWidget)
editorQWidget.released.connect(partial(self.requestNewPath, indexQModelIndex))
return editorQWidget
else:
return QtGui.QItemDelegate.createEditor(self, parentQWidget, optionQStyleOptionViewItem, indexQModelIndex)
def setEditorData (self, editorQWidget, indexQModelIndex):
column = indexQModelIndex.column()
if column == 0:
textQString = indexQModelIndex.model().data(indexQModelIndex, QtCore.Qt.EditRole).toString()
editorQWidget.setText(textQString)
else:
QtGui.QItemDelegate.setEditorData(self, editorQWidget, indexQModelIndex)
def setModelData (self, editorQWidget, modelQAbstractItemModel, indexQModelIndex):
column = indexQModelIndex.column()
if column == 0:
textQString = editorQWidget.text()
modelQAbstractItemModel.setData(indexQModelIndex, textQString, QtCore.Qt.EditRole)
else:
QtGui.QItemDelegate.setModelData(self, editorQWidget, modelQAbstractItemModel, indexQModelIndex)
def updateEditorGeometry(self, editorQWidget, optionQStyleOptionViewItem, indexQModelIndex):
column = indexQModelIndex.column()
if column == 0:
editorQWidget.setGeometry(optionQStyleOptionViewItem.rect)
else:
QtGui.QItemDelegate.updateEditorGeometry(self, editorQWidget, optionQStyleOptionViewItem, indexQModelIndex)
def requestNewPath (self, indexQModelIndex):
self.signalNewPath.emit(indexQModelIndex)
def paint (self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex):
column = indexQModelIndex.column()
if column == 0:
textQString = indexQModelIndex.model().data(indexQModelIndex, QtCore.Qt.EditRole).toString()
painterQPainter.drawPixmap (
optionQStyleOptionViewItem.rect.x(),
optionQStyleOptionViewItem.rect.y(),
QtGui.QPixmap(textQString).scaled(180, 180, QtCore.Qt.KeepAspectRatio))
else:
QtGui.QItemDelegate.paint(self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex)
class QCustomTreeWidget (QtGui.QTreeWidget):
def __init__(self, parent = None):
super(QCustomTreeWidget, self).__init__(parent)
self.setColumnCount(1)
myQCustomDelegate = QCustomDelegate()
self.setItemDelegate(myQCustomDelegate)
myQCustomDelegate.signalNewPath.connect(self.getNewPath)
def addMenu (self, path, parentQTreeWidgetItem = None):
if parentQTreeWidgetItem == None:
parentQTreeWidgetItem = self.invisibleRootItem()
currentQTreeWidgetItem = QtGui.QTreeWidgetItem(parentQTreeWidgetItem)
currentQTreeWidgetItem.setData(0, QtCore.Qt.EditRole, path)
currentQTreeWidgetItem.setFlags(currentQTreeWidgetItem.flags() | QtCore.Qt.ItemIsEditable)
for i in range(self.columnCount()):
currentQSize = currentQTreeWidgetItem.sizeHint(i)
currentQTreeWidgetItem.setSizeHint(i, QtCore.QSize(currentQSize.width(), currentQSize.height() + 200))
def getNewPath (self, indexQModelIndex):
currentQTreeWidgetItem = self.itemFromIndex(indexQModelIndex)
pathQStringList = QtGui.QFileDialog.getOpenFileNames()
if pathQStringList.count() > 0:
textQString = pathQStringList.first()
currentQTreeWidgetItem.setData(indexQModelIndex.column(), QtCore.Qt.EditRole, textQString)
print textQString
class QCustomQWidget (QtGui.QWidget):
def __init__ (self, parent = None):
super(QCustomQWidget, self).__init__(parent)
self.myQCustomTreeWidget = QCustomTreeWidget(self)
self.allQHBoxLayout = QtGui.QHBoxLayout()
self.allQHBoxLayout.addWidget(self.myQCustomTreeWidget)
self.setLayout(self.allQHBoxLayout)
self.myQCustomTreeWidget.addMenu(r'''C:\Users\Kitsune Meyoko\Desktop\twitter01.jpg''')
self.myQCustomTreeWidget.addMenu(r'''C:\Users\Kitsune Meyoko\Desktop\twitter02.jpg''')
self.myQCustomTreeWidget.addMenu(r'''C:\Users\Kitsune Meyoko\Desktop\twitter04.jpg''')
self.myQCustomTreeWidget.addMenu(r'''C:\Users\Kitsune Meyoko\Desktop\twitter05.jpg''')
app = QtGui.QApplication([])
myQCustomQWidget = QCustomQWidget()
myQCustomQWidget.show()
sys.exit(app.exec_())
Note: In same way to implement QTreeView, but different is set values only.
If your want to show image by path in some index (In this case : 2nd). Your can find it by using QModelIndex QAbstractItemModel.index (self, int row, int column, QModelIndex parent = QModelIndex()), And do want your want.
Example;
import sys
from PyQt4 import QtCore, QtGui
class QCustomDelegate (QtGui.QItemDelegate):
def paint (self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex):
column = indexQModelIndex.column()
if column == 3:
currentQAbstractItemModel = indexQModelIndex.model()
iconQModelIndex = currentQAbstractItemModel.index(indexQModelIndex.row(), 1, indexQModelIndex.parent())
pathQString = currentQAbstractItemModel.data(iconQModelIndex, QtCore.Qt.EditRole).toString()
iconQPixmap = QtGui.QPixmap(pathQString)
if not iconQPixmap.isNull():
painterQPainter.drawPixmap (
optionQStyleOptionViewItem.rect.x(),
optionQStyleOptionViewItem.rect.y(),
iconQPixmap.scaled(20, 20, QtCore.Qt.KeepAspectRatio))
else:
QtGui.QItemDelegate.paint(self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex)
myQApplication = QtGui.QApplication([])
myQTreeView = QtGui.QTreeView()
headerQStandardItemModel = QtGui.QStandardItemModel()
headerQStandardItemModel.setHorizontalHeaderLabels([''] * 4)
myQTreeView.setModel(headerQStandardItemModel)
# Set delegate
myQCustomDelegate = QCustomDelegate()
myQTreeView.setItemDelegate(myQCustomDelegate)
# Append data row 1
row1QStandardItem = QtGui.QStandardItem('ROW 1')
row1QStandardItem.appendRow([QtGui.QStandardItem(''), QtGui.QStandardItem('1.jpg'), QtGui.QStandardItem(''), QtGui.QStandardItem('')])
headerQStandardItemModel.appendRow(row1QStandardItem)
# Append data row 2
row2QStandardItem = QtGui.QStandardItem('ROW 2')
row2QStandardItem.appendRow([QtGui.QStandardItem(''), QtGui.QStandardItem('2.png'), QtGui.QStandardItem(''), QtGui.QStandardItem('')])
headerQStandardItemModel.appendRow(row2QStandardItem)
myQTreeView.show()
sys.exit(myQApplication.exec_())
experimental result:
Note: I have image 1.jpg, 2.png.

Item Checking not possible with UltimateListCtrl in ULC_VIRTUAL mode

Following is the system and software info
Platforms: Windows XP and OSX Lion
Activestate Python 2.7.2
wxPython2.9-osx-cocoa-py2.7 (for OSX)
wxPython2.9-win32-py27 (for Windows XP)
I am trying to create a UltimateListCtrl using ULC_VIRTUAL and ULC_REPORT mode. I would like to know how can I put a checkbox beside the first column of every row and catch the event when a user checks the box. I was able to do the same using UltimateListCtrl without VIRTUAL mode. But, with the ULC_VIRTUAL flag ON, I don't know how to proceed. Following is the code I created, but this still doesn't allow me to check the boxes associated with the first column. Please help.
import wx
import images
import random
import os, sys
from wx.lib.agw import ultimatelistctrl as ULC
class TestUltimateListCtrl(ULC.UltimateListCtrl):
def __init__(self, parent, log):
ULC.UltimateListCtrl.__init__(self, parent, -1, agwStyle=ULC.ULC_VIRTUAL|ULC.ULC_REPORT|ULC.ULC_SINGLE_SEL|ULC.ULC_VRULES|ULC.ULC_HRULES)
self.SetItemCount(1000)
self.table_fields=['First','Second','Third']
field_index=0
for field in self.table_fields:
info = ULC.UltimateListItem()
info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_CHECK
info._image = []
info._format = wx.LIST_FORMAT_CENTER
info._kind = 1
info._text = field
info._font= wx.Font(13, wx.ROMAN, wx.NORMAL, wx.BOLD)
self.InsertColumnInfo(field_index, info)
self.SetColumnWidth(field_index,175)
field_index += 1
def getColumnText(self, index, col):
item = self.GetItem(index, col)
return item.GetText()
def OnGetItemText(self, item, col):
return "Item %d, Column %d" % (item,col)
def OnGetItemColumnImage(self, item, col):
return []
def OnGetItemImage(self, item):
return []
def OnGetItemAttr(self, item):
return None
def OnGetItemTextColour(self, item, col):
return None
#def OnGetItemColumnCheck(self, item, col):
#return True
#def OnGetItemCheck(self, item):
#return True
def OnGetItemToolTip(self, item, col):
return None
def OnGetItemKind(self, item):
return 1
def OnGetItemColumnKind(self, item, col):
if col==0:
return self.OnGetItemKind(item)
return 0
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "UltimateListCtrl in wx.LC_VIRTUAL mode", size=(700, 600))
panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
listCtrl = TestUltimateListCtrl(panel, log)
sizer.Add(listCtrl, 1, wx.EXPAND)
panel.SetSizer(sizer)
sizer.Layout()
self.CenterOnScreen()
self.Show()
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
Btw, following is the code I used to create the same thing without the VIRTUAL mode. And in this case, I can check the boxes beside the first column data in every row. But, I will be working with tens of thousands of items and I cannot rely on loading the items like below because it is very slow. Hence, I want to use the Virtual List, but I don't know how to get the same functionality in it.
import wx
import images
import random
import os, sys
from wx.lib.agw import ultimatelistctrl as ULC
class TestUltimateListCtrl(ULC.UltimateListCtrl):
def __init__(self, parent, log):
ULC.UltimateListCtrl.__init__(self, parent, -1, agwStyle=ULC.ULC_REPORT|ULC.ULC_SINGLE_SEL|ULC.ULC_VRULES|ULC.ULC_HRULES)
self.table_fields=['First','Second','Third']
field_index=0
for field in self.table_fields:
info = ULC.UltimateListItem()
info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_CHECK
info._image = []
info._format = wx.LIST_FORMAT_CENTER
info._kind = 1
info._text = field
info._font= wx.Font(13, wx.ROMAN, wx.NORMAL, wx.BOLD)
self.InsertColumnInfo(field_index, info)
self.SetColumnWidth(field_index,175)
field_index += 1
for record_index in range(0,1000):
for field in self.table_fields:
if self.table_fields.index(field)==0:
self.InsertStringItem(record_index, 'Item %d, Column %d' % (record_index,self.table_fields.index(field)),it_kind=1)
else:
self.SetStringItem(record_index, self.table_fields.index(field), 'Item %d, Column %d' % (record_index,self.table_fields.index(field)))
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "UltimateListCtrl in wx.LC_VIRTUAL mode", size=(700, 600))
panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
listCtrl = TestUltimateListCtrl(panel, log)
sizer.Add(listCtrl, 1, wx.EXPAND)
panel.SetSizer(sizer)
sizer.Layout()
self.CenterOnScreen()
self.Show()
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()
This question has been here for a while and I've been trying to find a solution to this problem around the web (to no avail). I've now solved mine and I'm posting here just in case someone might find the solution useful, or may have an more appropriate one.
Short answer: you will need to manually keep track of checked and unchecked items. To detect which are being checked (clicked), you can bind to the EVT_LIST_ITEM_CHECKING event.
Long answer: First, you will need a way to keep track of which items are checked or not. Then use that for determining what to return for OnGetItemColumnCheck. You could, for example, use a list of item+columns like so:
def __init__(...):
...
self.checked = []
...
def OnGetItemColumnCheck(self, item, column):
item_column = (item, column)
if item_column in self.checked:
return True
else:
return False
You will now need a way to populate that list. To do that, you will need to bind to the EVT_LIST_ITEM_CHECKING and do the appropriate actions:
def __init__(...):
...
self.checked = []
self.Bind(ULC.EVT_LIST_ITEM_CHECKING, self.OnCheck)
...
def OnCheck(self, event):
item_column = (event.m_itemIndex, event.m_item.GetColumn())
try:
idx = self.checked.index(item_column)
except ValueError:
idx = None
if idx == None:
self.checked.append(item_column)
else:
del(self.checked[idx])
self.Refresh()
The self.Refresh() call is essential as sometimes the checkbox won't get redrawn. After this, you should now be able to check and uncheck items (and that information is easily accessible to boot!). Here is your complete code with the above modifications:
import wx
import random
import os, sys
from wx.lib.agw import ultimatelistctrl as ULC
class TestUltimateListCtrl(ULC.UltimateListCtrl):
def __init__(self, parent, log):
ULC.UltimateListCtrl.__init__(self, parent, -1, agwStyle=ULC.ULC_VIRTUAL|ULC.ULC_REPORT|ULC.ULC_SINGLE_SEL|ULC.ULC_VRULES|ULC.ULC_HRULES)
self.SetItemCount(1000)
self.table_fields=['First','Second','Third']
field_index=0
for field in self.table_fields:
info = ULC.UltimateListItem()
info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_CHECK
info._image = []
info._format = wx.LIST_FORMAT_CENTER
info._kind = 1
info._text = field
info._font= wx.Font(13, wx.ROMAN, wx.NORMAL, wx.BOLD)
self.InsertColumnInfo(field_index, info)
self.SetColumnWidth(field_index,175)
field_index += 1
self.checked = []
self.Bind(ULC.EVT_LIST_ITEM_CHECKING, self.OnCheck)
def OnCheck(self, event):
item_column = (event.m_itemIndex, event.m_item.GetColumn())
try:
idx = self.checked.index(item_column)
except ValueError:
idx = None
if idx == None:
self.checked.append(item_column)
else:
del(self.checked[idx])
self.Refresh()
def getColumnText(self, index, col):
item = self.GetItem(index, col)
return item.GetText()
def OnGetItemText(self, item, col):
return "Item %d, Column %d" % (item,col)
def OnGetItemColumnImage(self, item, col):
return []
def OnGetItemImage(self, item):
return []
def OnGetItemAttr(self, item):
return None
def OnGetItemTextColour(self, item, col):
return None
def OnGetItemToolTip(self, item, col):
return None
def OnGetItemKind(self, item):
return 1
def OnGetItemColumnKind(self, item, col):
if col==0:
return self.OnGetItemKind(item)
return 0
def OnGetItemColumnCheck(self, item, column):
item_column = (item, column)
if item_column in self.checked:
return True
else:
return False
class TestFrame(wx.Frame):
def __init__(self, parent, log):
wx.Frame.__init__(self, parent, -1, "UltimateListCtrl in wx.LC_VIRTUAL mode", size=(700, 600))
panel = wx.Panel(self, -1)
sizer = wx.BoxSizer(wx.VERTICAL)
listCtrl = TestUltimateListCtrl(panel, log)
sizer.Add(listCtrl, 1, wx.EXPAND)
panel.SetSizer(sizer)
sizer.Layout()
self.CenterOnScreen()
self.Show()
if __name__ == '__main__':
import sys
app = wx.PySimpleApp()
frame = TestFrame(None, sys.stdout)
frame.Show(True)
app.MainLoop()

Resources