Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import random
- import time
- from sortedcontainers import SortedDict
- # Define the database. At this point it comprises a single SortedDict in
- # which the keys are rwt(8) "word" tokens, and the values are tuples
- # comprising ( word, int in 0-99, rft() flag string). Yes this is
- # redundant in having the word as both key and value but it simplifies
- # coding the data() method of the model.
- DBM = SortedDict()
- DBV = None # valuesview
- DBS = 10000 # how many rows
- # These functions are used to populate the database with
- # values that are kinda-sorta like the ones in my app.
- def xdi(B,N,M):
- '''
- eXponential Distribution of Integers, XDI
- Return a list of length N of integers with max value M, from an exponential
- distribution with beta B.
- '''
- M = int(M) # just in case
- # pre-allocate the list rather than building it with .append()
- r = [0]*N
- for j in range(N) :
- r[j] = int( random.expovariate(B) ) % M
- return r
- RWTALPH = 'aeiouåáïbcdfghjklmnpqrstvwxyz_BCDFGHJKLMNPQRSTVWZ'
- def rwt(N):
- '''
- Random Word-like Token, RWT
- Return a word-like token comprising N Latin-1 letters with an
- emphasis on vowels.
- '''
- ii = xdi( 0.1, N, len(RWTALPH)-1 )
- return ''.join( [ RWTALPH[i] for i in ii ] )
- def rft():
- '''
- Random Flag Token
- Return an 8-char token composed mostly of dashes with a sprinkle of Xs,
- e.g. "---X--X-" or "XX------".
- '''
- ii = xdi( 2, 8, 2 )
- return ''.join( ['-X'[i] for i in ii ] )
- # Clear the database, called before Refresh
- def clear_the_db() :
- global DBM, DBV
- DBM.clear()
- DBV = None
- # Rebuild the database, called on a Refresh.
- def rebuild_the_db():
- global DBM, DBV, DBS
- '''
- [re]populate the fake database:
- * Create a vector of random numbers which will constitute
- Column 2 and also pace the creation loop
- * Clear the SortedDict and load it with DBS rows of fake data
- * Recreate the keysview and valuesview
- '''
- col2 = xdi( 0.05, DBS, 100 )
- assert DBS == len(col2) # once in a blue moon...
- clear_the_db()
- for k in col2 :
- w = rwt(8)
- f = rft()
- DBM[ w ] = ( w, k, f )
- DBV = DBM.values()
- # Define the Table Model, instrumented to count certain calls
- from PyQt5.QtCore import Qt, QAbstractTableModel
- class Model( QAbstractTableModel ):
- def __init__ ( self, parent=None ) :
- super().__init__( parent )
- self.access_counts = [0, 0, 0]
- def rowCount( self, index ) :
- global DBM
- if index.isValid() : return 0
- return len(DBM)
- def columnCount( self, index ) :
- if index.isValid() : return 0
- return 3
- def data(self, index, role ) :
- global DBV
- if role != Qt.DisplayRole :
- return None
- row = index.row()
- col = index.column()
- self.access_counts[col] += 1
- return DBV[ row ][ col ]
- def clear_counts( self ) :
- self.access_counts = [0, 0, 0]
- def counts( self ) :
- return list( self.access_counts )
- # Define the Table View, which at this point is quite minimal.
- # The View is instantiated from MainWindow, which also connects
- # the model to it.
- from PyQt5.QtWidgets import QTableView
- class View( QTableView ):
- def __init__ ( self, parent=None ) :
- super().__init__( parent )
- self.setSortingEnabled( True )
- self.sortByColumn( 0, Qt.AscendingOrder )
- # Define the SortFilterProxy, which at this point is quite minimal.
- # It too is instantiated by the Mainwindow.
- from PyQt5.QtCore import QSortFilterProxyModel
- class Proxy( QSortFilterProxyModel ) :
- def __init__ ( self, parent=None ) :
- super().__init__( parent )
- self.setSortCaseSensitivity( True )
- self.setSortLocaleAware( True )
- # Define the main window which is the visual face of this app.
- from PyQt5.QtWidgets import (
- QLabel,
- QMainWindow,
- QPushButton,
- QVBoxLayout,
- QHBoxLayout,
- QWidget
- )
- class Main( QMainWindow ) :
- def __init__ ( self ) :
- super().__init__( )
- self.times = [0, 0, 0]
- clear_the_db() # make sure to start with 0 rows
- self._uic() # all the layout stuff out of line
- self.refresh_button.clicked.connect( self.do_refresh )
- # Slot called when Refresh is clicked:
- # * clear the counts
- # * start model reset
- # * rebuild the DBM, timing it
- # * end the model reset, timing that
- # * update the labels displaying call counts and times
- def do_refresh( self ) :
- self.table_model.clear_counts()
- self.table_model.beginResetModel()
- self.times[0] = time.process_time()
- rebuild_the_db()
- self.times[1] = time.process_time()
- self.table_model.endResetModel()
- QApplication.processEvents()
- self.times[2] = time.process_time()
- self.update_labels()
- def update_labels(self) :
- [c0, c1, c2] = self.table_model.counts()
- [t0, t1, t2] = self.times
- self.c0_label.setText( str(c0) )
- self.c1_label.setText( str(c1) )
- self.c2_label.setText( str(c2) )
- self.td_label.setText( '{:02.5f}'.format(t1-t0) )
- self.tr_label.setText( '{:02.5f}'.format(t2-t1) )
- def _make_label( self, text='0' ) :
- # just make a right-aligned label out of line
- L = QLabel(text)
- L.setAlignment( Qt.AlignRight | Qt.AlignVCenter )
- return L
- def _uic( self ) :
- # create the table model, view and proxy
- self.table_view = View( parent=self )
- self.table_model = Model( parent=self )
- self.table_proxy = Proxy( parent=self )
- self.table_proxy.setSourceModel( self.table_model )
- self.table_view.setModel( self.table_proxy )
- # create the refresh button, put it in an hbox by itself, for now
- self.refresh_button = QPushButton( "Refresh" )
- hb0 = QHBoxLayout()
- hb0.addWidget(self.refresh_button, 0)
- hb0.addStretch(1)
- # create a set of labels to display counts of
- # entry to the model.data() method and times
- self.c0_label = self._make_label() # display role calls to column 0
- self.c1_label = self._make_label() # 1
- self.c2_label = self._make_label() # 2
- self.tr_label = self._make_label() # time to reset the model
- self.td_label = self._make_label() # time to rebuild the db
- # build the row of call numbers
- hb1 = QHBoxLayout()
- hb1.addStretch(1) # push this row to the right
- hb1.addWidget( self._make_label( 'Display role calls col 0:' ) )
- hb1.addWidget( self.c0_label )
- hb1.addStretch(0)
- hb1.addWidget( self._make_label( 'col 1:' ) )
- hb1.addWidget( self.c1_label )
- hb1.addStretch(0)
- hb1.addWidget( self._make_label( 'col 2:' ) )
- hb1.addWidget( self.c2_label )
- # build the row of times
- hb2 = QHBoxLayout()
- hb2.addStretch(1)
- hb2.addWidget( self._make_label( 'Seconds to build DB:' ) )
- hb2.addWidget( self.td_label )
- hb2.addStretch(0)
- hb2.addWidget( self._make_label( 'to reset model:' ) )
- hb2.addWidget( self.tr_label )
- # stack up the central layout
- vb = QVBoxLayout()
- vb.addLayout( hb0, 0 )
- vb.addWidget( self.table_view, 1 )
- vb.addLayout( hb1, 0 )
- vb.addLayout( hb2, 0 )
- # put all that in a widget and make the widget our central layout
- wij = QWidget()
- wij.setLayout( vb )
- wij.setMinimumSize( 500, 500 )
- self.setCentralWidget( wij )
- if __name__ == '__main__' :
- from PyQt5.QtWidgets import QApplication
- the_app = QApplication([])
- main_window = Main()
- main_window.show()
- the_app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement