Advertisement
fernly

QSFPM-test.py

Mar 24th, 2015
270
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.35 KB | None | 0 0
  1. import random
  2. import time
  3. from sortedcontainers import SortedDict
  4.  
  5. # Define the database. At this point it comprises a single SortedDict in
  6. # which the keys are rwt(8) "word" tokens, and the values are tuples
  7. # comprising ( word, int in 0-99). Yes this is
  8. # redundant in having the word as both key and value but it simplifies
  9. # coding the data() method of the model.
  10.  
  11. DBM = SortedDict()
  12. DBV = DBM.values()
  13.  
  14. DBS = 10000 # how many rows: can be set from sys.argv[1]
  15.  
  16. # These functions are used to populate the database with
  17. # values that are kinda-sorta like the ones in my app.
  18.  
  19. def xdi(B,N,M):
  20.     '''
  21.            eXponential Distribution of Integers, XDI
  22.    Return a list of length N of integers with max value M, from an exponential
  23.    distribution with beta B.
  24.    '''
  25.     M = int(M) # just in case
  26.     # pre-allocate the list rather than building it with .append()
  27.     r = [0]*N
  28.     for j in range(N) :
  29.         r[j] = int( random.expovariate(B) ) % M
  30.     return r
  31.  
  32. RWTALPH = 'aeiouåáïbcdfghjklmnpqrstvwxyz_BCDFGHJKLMNPQRSTVWZ'
  33. def rwt(N):
  34.     '''
  35.            Random Word-like Token, RWT
  36.    Return a word-like token comprising N Latin-1 letters with an
  37.    emphasis on vowels.
  38.    '''
  39.     ii = xdi( 0.1, N, len(RWTALPH)-1 )
  40.     return ''.join( [ RWTALPH[i] for i in ii ] )
  41.  
  42. # Rebuild the database, called on a Refresh.
  43.  
  44. def rebuild_the_db():
  45.     global DBM, DBV, DBS
  46.     '''
  47.    [re]populate the fake database:
  48.    * Create a vector of random numbers which will constitute
  49.      Column 2 and also pace the creation loop
  50.    * Clear the SortedDict and load it with DBS rows of fake data
  51.    * Recreate the valuesview
  52.    '''
  53.     DBM.clear()
  54.     DBV = None
  55.     col2 = xdi( 0.05, DBS, 100 )
  56.     for k in col2 :
  57.         w = rwt(8)
  58.         DBM[ w ] = ( w, k )
  59.     DBV = DBM.values()
  60.  
  61. # Define the Table Model, instrumented to count certain calls
  62.  
  63. from PyQt5.QtCore import Qt, QAbstractTableModel
  64.  
  65. class Model( QAbstractTableModel ):
  66.     def __init__ ( self, parent=None ) :
  67.         super().__init__( parent )
  68.         self.clear_counts()
  69.  
  70.     def clear_counts( self ) :
  71.         self.access_counts = [0, 0] # accesses to data(0 or 1)
  72.         self.sort_time = 0.0 # see proxy sort()
  73.  
  74.     def counts( self ) :
  75.         return list( self.access_counts )
  76.     def times( self ) :
  77.         return self.sort_time
  78.  
  79.     def rowCount( self, index ) :
  80.         global DBM
  81.         if index.isValid() : return 0
  82.         return len(DBM)
  83.  
  84.     def columnCount( self, index ) :
  85.         if index.isValid() : return 0
  86.         return 2
  87.  
  88.     def data(self, index, role ) :
  89.         global DBV
  90.         if role != Qt.DisplayRole :
  91.             return None
  92.         row = index.row()
  93.         col = index.column()
  94.         self.access_counts[col] += 1
  95.         return DBV[ row ][ col ]
  96.  
  97. # Define the Table View, which at this point is quite minimal.
  98. # The View is instantiated from MainWindow, which also connects
  99. # the model to it.
  100.  
  101. from PyQt5.QtWidgets import QTableView
  102.  
  103. class View( QTableView ):
  104.     def __init__ ( self, parent=None ) :
  105.         super().__init__( parent )
  106.         self.setSortingEnabled( True )
  107.         self.sortByColumn( 0, Qt.AscendingOrder )
  108.  
  109. # Define the SortFilterProxy which is the stock item except for
  110. # an override of the sort() method to take timings, and to emit
  111. # a signal when a sort is finished.
  112. #
  113. # It too is instantiated by the Mainwindow.
  114.  
  115. from PyQt5.QtCore import QSortFilterProxyModel, pyqtSignal
  116.  
  117. class Proxy( QSortFilterProxyModel ) :
  118.  
  119.     sortFinished = pyqtSignal() # declare own signal
  120.  
  121.     def __init__ ( self, parent=None ) :
  122.         super().__init__( parent )
  123.         self.setSortCaseSensitivity( True )
  124.         self.setSortLocaleAware( True )
  125.  
  126.     def sort( self, column, order ) :
  127.         self.sourceModel().clear_counts()
  128.         t0 = time.process_time()
  129.         super().sort( column, order ) # do the real sort
  130.         self.sourceModel().sort_time = time.process_time() - t0
  131.         self.sortFinished.emit()
  132.  
  133. # Define the main window which is the visual face of this app.
  134.  
  135. from PyQt5.QtWidgets import (
  136.     QLabel,
  137.     QMainWindow,
  138.     QPushButton,
  139.     QVBoxLayout,
  140.     QHBoxLayout,
  141.     QWidget
  142.     )
  143.  
  144. class Main( QMainWindow ) :
  145.     def __init__ ( self ) :
  146.         super().__init__( )
  147.         self.times = [0, 0, 0]
  148.         self._uic() # all the layout stuff out of line
  149.         self.refresh_button.clicked.connect( self.do_refresh )
  150.         self.table_proxy.sortFinished.connect( self.update_labels )
  151.  
  152.     # Slot called when Refresh is clicked:
  153.     # * clear the counts
  154.     # * start model reset
  155.     # * rebuild the DBM
  156.     # * end the model reset
  157.  
  158.     def do_refresh( self ) :
  159.         self.table_model.clear_counts()
  160.         self.table_model.beginResetModel()
  161.         rebuild_the_db()
  162.         self.table_model.endResetModel()
  163.  
  164.     def update_labels(self) :
  165.         [c0, c1] = self.table_model.counts()
  166.         ts = self.table_model.times()
  167.         self.c0_label.setText( str(c0) )
  168.         self.c1_label.setText( str(c1) )
  169.         self.ts_label.setText( '{:02.5f}'.format(ts) )
  170.  
  171.     def _make_label( self, text='0' ) :
  172.         # just make a right-aligned label out of line
  173.         L = QLabel(text)
  174.         L.setAlignment( Qt.AlignRight | Qt.AlignVCenter )
  175.         return L
  176.  
  177.     def _uic( self ) :
  178.         # create the table model, view and proxy
  179.         self.table_view = View( parent=self )
  180.         self.table_model = Model( parent=self )
  181.         self.table_proxy = Proxy( parent=self )
  182.         self.table_proxy.setSourceModel( self.table_model )
  183.         self.table_view.setModel( self.table_proxy )
  184.         # create the refresh button, put it in an hbox by itself
  185.         self.refresh_button = QPushButton( "Refresh" )
  186.         hb0 = QHBoxLayout()
  187.         hb0.addWidget(self.refresh_button, 0)
  188.         hb0.addStretch(1)
  189.         # create a set of labels to display counts of
  190.         # entry to the model.data() method and times
  191.         self.c0_label = self._make_label() # display-role calls to column 0
  192.         self.c1_label = self._make_label() # 1
  193.         self.ts_label = self._make_label() # time to perform a column sort
  194.         # build the row of call numbers
  195.         hb1 = QHBoxLayout()
  196.         hb1.addStretch(1) # push this row to the right
  197.         hb1.addWidget( self._make_label( 'Display-role calls for col 0:' ) )
  198.         hb1.addWidget( self.c0_label )
  199.         hb1.addStretch(0)
  200.         hb1.addWidget( self._make_label( 'col 1:' ) )
  201.         hb1.addWidget( self.c1_label )
  202.         # build the row of times
  203.         hb2 = QHBoxLayout()
  204.         hb2.addStretch(1)
  205.         hb2.addWidget( self._make_label( 'CPU seconds to sort:' ) )
  206.         hb2.addWidget( self.ts_label )
  207.         # stack up the central layout
  208.         vb = QVBoxLayout()
  209.         vb.addLayout( hb0, 0 )
  210.         vb.addWidget( self.table_view, 1 )
  211.         vb.addLayout( hb1, 0 )
  212.         vb.addLayout( hb2, 0 )
  213.         # put all that in a widget and make the widget our central layout
  214.         wij = QWidget()
  215.         wij.setLayout( vb )
  216.         wij.setMinimumSize( 500, 500 )
  217.         self.setCentralWidget( wij )
  218.  
  219.  
  220. if __name__ == '__main__' :
  221.     from PyQt5.QtWidgets import QApplication
  222.     import sys
  223.     try:
  224.         DBS = int(sys.argv[1])
  225.     except Exception as whatever :
  226.         DBS = 10000
  227.     the_app = QApplication(sys.argv)
  228.     main_window = Main()
  229.     main_window.show()
  230.     the_app.exec_()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement