Browse Source

2017-03-17:experimented with qtgui range widget updates, LyX: tables,flowgraph-pngs, rds group structure-pngs

master
Clemens Richter 9 years ago
parent
commit
6d3278c846
  1. 3
      grc/CMakeLists.txt
  2. 130
      grc/crfa_qtgui_range.xml
  3. 3
      python/CMakeLists.txt
  4. 1
      python/__init__.py
  5. 266
      python/qtgui_range.py
  6. 1
      python/qtguitest.py
  7. 20
      python/rds_parser_table_qt.py

3
grc/CMakeLists.txt

@ -29,5 +29,6 @@ install(FILES
crfa_decoder_compare.xml crfa_decoder_compare.xml
crfa_diff_add_sync_decim.xml crfa_diff_add_sync_decim.xml
crfa_sync_decim.xml crfa_sync_decim.xml
crfa_rds_decoder_redsea.xml DESTINATION share/gnuradio/grc/blocks crfa_rds_decoder_redsea.xml
crfa_qtgui_range.xml DESTINATION share/gnuradio/grc/blocks
) )

130
grc/crfa_qtgui_range.xml

@ -0,0 +1,130 @@
<?xml version="1.0"?>
<block>
<name>qtgui_range (cr)</name>
<key>variable_crfa_qtgui_range</key>
<category>[crfa]</category>
<import>import crfa</import>
<import>from crfa.qtgui_range import qtgui_range, RangeWidget</import>
<var_make>self.$(id) = $(id) = $value</var_make>
<make>#set $win = 'self._%s_win'%$id
#set $range = 'self.%s_range'%$id
#if not $label()
#set $label = '"%s"'%$id
#end if
$(range) = qtgui_range($start, $stop, $step, $value, $min_len)
$(win) = RangeWidget($range, self.set_$(id), $label, "$widget", $rangeType)
$(gui_hint()($win))</make>
<callback>self.freq2_range.set_test($value);</callback>
<callback>self.set_$(id)($value)</callback>
<param>
<name>Label</name>
<key>label</key>
<value></value>
<type>string</type>
<hide>#if $label() then 'none' else 'part'#</hide>
</param>
<param>
<name>Type</name>
<key>rangeType</key>
<value>"float"</value>
<type>enum</type>
<hide>part</hide>
<option><name>Float</name><key>float</key><opt>type:float</opt></option>
<option><name>Int</name><key>int</key><opt>type:int</opt></option>
</param>
<param>
<name>Default Value</name>
<key>value</key>
<value>50</value>
<type>$rangeType.type</type>
</param>
<param>
<name>Start</name>
<key>start</key>
<value>0</value>
<type>$rangeType.type</type>
</param>
<param>
<name>Stop</name>
<key>stop</key>
<value>100</value>
<type>$rangeType.type</type>
</param>
<param>
<name>Step</name>
<key>step</key>
<value>1</value>
<type>$rangeType.type</type>
</param>
<param>
<name>Widget</name>
<key>widget</key>
<value>counter_slider</value>
<type>enum</type>
<hide>part</hide>
<option><name>Counter + Slider</name><key>counter_slider</key></option>
<option><name>Counter</name><key>counter</key></option>
<option><name>Slider</name><key>slider</key></option>
<option><name>Knob</name><key>dial</key></option>
</param>
<param>
<name>Orientation</name>
<key>orient</key>
<value>Qt.Horizontal</value>
<type>enum</type>
<hide>#if $widget() == "slider" then 'part' else 'all'#</hide>
<option>
<name>Horizontal</name>
<key>Qt.Horizontal</key>
<opt>scalepos:BottomScale</opt>
<opt>minfcn:setMinimumWidth</opt>
</option>
<option>
<name>Vertical</name>
<key>Qt.Vertical</key>
<opt>scalepos:LeftScale</opt>
<opt>minfcn:setMinimumHeight</opt>
</option>
</param>
<param>
<name>Minimum Length</name>
<key>min_len</key>
<value>200</value>
<type>int</type>
<hide>part</hide>
</param>
<!-- from min_len <hide>#if $widget().split('_')[0] in ("slider", "counter") then 'part' else 'all'#</hide>-->
<param>
<name>GUI Hint</name>
<key>gui_hint</key>
<value></value>
<type>gui_hint</type>
<hide>part</hide>
</param>
<check>$start &lt;= $value &lt;= $stop</check>
<check>$start &lt; $stop</check>
<doc>
This block creates a variable with a slider. \
Leave the label blank to use the variable id as the label. \
The value must be a real number. \
The value must be between the start and the stop.
The GUI hint can be used to position the widget within the application. \
The hint is of the form [tab_id@tab_index]: [row, col, row_span, col_span]. \
Both the tab specification and the grid position are optional.
</doc>
</block>

3
python/CMakeLists.txt

@ -40,7 +40,8 @@ GR_PYTHON_INSTALL(
chart.py chart.py
stream_selector.py stream_selector.py
vector_cutter.py vector_cutter.py
decoder_compare.py DESTINATION ${GR_PYTHON_DIR}/crfa decoder_compare.py
qtgui_range.py DESTINATION ${GR_PYTHON_DIR}/crfa
) )
######################################################################## ########################################################################

1
python/__init__.py

@ -41,4 +41,5 @@ from chart import Chart
from stream_selector import stream_selector from stream_selector import stream_selector
from vector_cutter import vector_cutter from vector_cutter import vector_cutter
from decoder_compare import decoder_compare from decoder_compare import decoder_compare
from qtgui_range import qtgui_range
# #

266
python/qtgui_range.py

@ -0,0 +1,266 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# Copyright 2015 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# GNU Radio is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3, or (at your option)
# any later version.
#
# GNU Radio is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNU Radio; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street,
# Boston, MA 02110-1301, USA.
#
from PyQt4 import Qt, QtCore, QtGui
class qtgui_range(object):
def set_test(self,value):
print("test callback invoked")
print(value)
def __init__(self, minv, maxv, step, default, min_length):
self.min = float(minv)
self.max = float(maxv)
self.step = float(step)
self.default = float(default)
self.min_length = min_length
self.find_precision()
self.find_nsteps()
def find_precision(self):
# Get the decimal part of the step
temp = str(float(self.step) - int(self.step))[2:]
precision = len(temp) if temp is not '0' else 0
precision = min(precision, 13)
if precision == 0 and self.max < 100:
self.precision = 1 # Always have a decimal in this case
else:
self.precision = (precision + 2) if precision > 0 else 0
def find_nsteps(self):
self.nsteps = (self.max + self.step - self.min)/self.step
def demap_range(self, val):
if val > self.max:
val = self.max
if val < self.min:
val = self.min
return ((val-self.min)/self.step)
def map_range(self, val):
if val > self.nsteps:
val = self.max
if val < 0:
val = 0
return (val*self.step+self.min)
class RangeWidget(QtGui.QWidget):
def set_test(value):
print("test callback invoked on widget")
print(value)
def __init__(self, ranges, slot, label, style, rangeType=float):
""" Creates the QT Range widget """
QtGui.QWidget.__init__(self)
self.range = ranges
self.style = style
# rangeType tells the block how to return the value as a standard
self.rangeType = rangeType
# Top-block function to call when any value changes
# Some widgets call this directly when their value changes.
# Others have intermediate functions to map the value into the right range.
self.notifyChanged = slot
layout = Qt.QHBoxLayout()
label = Qt.QLabel(label)
layout.addWidget(label)
if style == "dial":
self.d_widget = self.Dial(self, self.range, self.notifyChanged, rangeType)
elif style == "slider":
self.d_widget = self.Slider(self, self.range, self.notifyChanged, rangeType)
elif style == "counter":
# The counter widget can be directly wired to the notifyChanged slot
self.d_widget = self.Counter(self, self.range, self.notifyChanged, rangeType)
else:
# The CounterSlider needs its own internal handlers before calling notifyChanged
self.d_widget = self.CounterSlider(self, self.range, self.notifyChanged, rangeType)
layout.addWidget(self.d_widget)
self.setLayout(layout)
class Dial(QtGui.QDial):
""" Creates the range using a dial """
def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QDial.__init__(self, parent)
self.rangeType = rangeType
# Setup the dial
self.setRange(0, ranges.nsteps-1)
self.setSingleStep(1)
self.setNotchesVisible(True)
self.range = ranges
# Round the initial value to the closest tick
temp = int(round(ranges.demap_range(ranges.default), 0))
self.setValue(temp)
# Setup the slots
self.valueChanged.connect(self.changed)
self.notifyChanged = slot
def changed(self, value):
""" Handles maping the value to the right range before calling the slot. """
val = self.range.map_range(value)
self.notifyChanged(self.rangeType(val))
class Slider(QtGui.QSlider):
""" Creates the range using a slider """
def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QSlider.__init__(self, QtCore.Qt.Horizontal, parent)
self.rangeType = rangeType
# Setup the slider
#self.setFocusPolicy(QtCore.Qt.NoFocus)
self.setRange(0, ranges.nsteps - 1)
self.setTickPosition(2)
self.setSingleStep(1)
self.range = ranges
# Round the initial value to the closest tick
temp = int(round(ranges.demap_range(ranges.default), 0))
self.setValue(temp)
if ranges.nsteps > ranges.min_length:
interval = int(ranges.nsteps/ranges.min_length)
self.setTickInterval(interval)
self.setPageStep(interval)
else:
self.setTickInterval(1)
self.setPageStep(1)
# Setup the handler function
self.valueChanged.connect(self.changed)
self.notifyChanged = slot
def changed(self, value):
""" Handle the valueChanged signal and map the value into the correct range """
print("gui changed")
val = self.range.map_range(value)
self.notifyChanged(self.rangeType(val))
def mousePressEvent(self, event):
if((event.button() == QtCore.Qt.LeftButton)):
new = self.minimum() + ((self.maximum()-self.minimum()) * event.x()) / self.width()
self.setValue(new)
event.accept()
# Use repaint rather than calling the super mousePressEvent.
# Calling super causes issue where slider jumps to wrong value.
QtGui.QSlider.repaint(self)
def mouseMoveEvent(self, event):
new = self.minimum() + ((self.maximum()-self.minimum()) * event.x()) / self.width()
self.setValue(new)
event.accept()
QtGui.QSlider.repaint(self)
class Counter(QtGui.QDoubleSpinBox):
""" Creates the range using a counter """
def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QDoubleSpinBox.__init__(self, parent)
self.rangeType = rangeType
# Setup the counter
self.setRange(ranges.min, ranges.max)
self.setValue(ranges.default)
self.setSingleStep(ranges.step)
self.setKeyboardTracking(False)
self.setDecimals(ranges.precision)
# The counter already handles floats and can be connected directly.
self.valueChanged.connect(self.changed)
self.notifyChanged = slot
def changed(self, value):
""" Handle the valueChanged signal by converting to the right type """
self.notifyChanged(self.rangeType(value))
class CounterSlider(QtGui.QWidget):
""" Creates the range using a counter and slider """
def __init__(self, parent, ranges, slot, rangeType=float):
QtGui.QWidget.__init__(self, parent)
self.rangeType = rangeType
# Slot to call in the parent
self.notifyChanged = slot
self.slider = RangeWidget.Slider(parent, ranges, self.sliderChanged, rangeType)
self.counter = RangeWidget.Counter(parent, ranges, self.counterChanged, rangeType)
# Need another horizontal layout to wrap the other widgets.
layout = Qt.QHBoxLayout()
layout.addWidget(self.slider)
layout.addWidget(self.counter)
self.setLayout(layout)
# Flag to ignore the slider event caused by a change to the counter.
self.ignoreSlider = False
self.range = ranges
def sliderChanged(self, value):
""" Handles changing the counter when the slider is updated """
# If the counter was changed, ignore any of these events
if not self.ignoreSlider:
# Value is already float. Just set the counter
self.counter.setValue(self.rangeType(value))
self.notifyChanged(self.rangeType(value))
self.ignoreSlider = False
def counterChanged(self, value):
""" Handles changing the slider when the counter is updated """
# Get the current slider value and check to see if the new value changes it
current = self.slider.value()
new = int(round(self.range.demap_range(value), 0))
# If it needs to change, ignore the slider event
# Otherwise, the slider will cause the counter to round to the nearest tick
if current != new:
self.ignoreSlider = True
self.slider.setValue(new)
self.notifyChanged(self.rangeType(value))
if __name__ == "__main__":
from PyQt4 import Qt
import sys
def valueChanged(frequency):
print("Value updated - " + str(frequency))
app = Qt.QApplication(sys.argv)
widget = RangeWidget(qtgui_range(0, 100, 10, 1, 100), valueChanged, "Test", "counter_slider", int)
widget.show()
widget.setWindowTitle("Test Qt Range")
app.exec_()
widget = None

1
python/qtguitest.py

@ -125,6 +125,7 @@ class CRWidget(QtGui.QWidget):
self.location_filter=QtGui.QLineEdit() self.location_filter=QtGui.QLineEdit()
self.button = QtGui.QPushButton("i am a button") self.button = QtGui.QPushButton("i am a button")
self.button.clicked.connect(self.onCLick)
layout.addWidget(self.button) layout.addWidget(self.button)
#self.filter_label=QtGui.QLabel() #self.filter_label=QtGui.QLabel()

20
python/rds_parser_table_qt.py

@ -31,7 +31,7 @@ from PyQt4 import Qt, QtCore, QtGui
import pprint,code,pickle#for easier testing import pprint,code,pickle#for easier testing
pp = pprint.PrettyPrinter() pp = pprint.PrettyPrinter()
import cProfile, pstats, StringIO #for profiling import cProfile, pstats, StringIO #for profiling
pr = cProfile.Profile()#disabled-internal-profiling pr = cProfile.Profile()
#from threading import Timer#to periodically save DB #from threading import Timer#to periodically save DB
@ -1846,16 +1846,16 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
details_button=QtGui.QPushButton("Detail") details_button=QtGui.QPushButton("Detail")
details_button.clicked.connect(functools.partial(self.getDetails, row=rowPosition)) details_button.clicked.connect(functools.partial(self.getDetails, row=rowPosition))
button_layout.addWidget(details_button) button_layout.addWidget(details_button)
left_button=QtGui.QPushButton("L") #2017-03-17 disabled LR buttons
left_button.clicked.connect(functools.partial(self.setAudio, row=rowPosition,audio_channel="left")) #left_button=QtGui.QPushButton("L")
button_layout.addWidget(left_button) #left_button.clicked.connect(functools.partial(self.setAudio, row=rowPosition,audio_channel="left"))
right_button=QtGui.QPushButton("R") #button_layout.addWidget(left_button)
right_button.clicked.connect(functools.partial(self.setAudio, row=rowPosition,audio_channel="right")) #right_button=QtGui.QPushButton("R")
button_layout.addWidget(right_button) #right_button.clicked.connect(functools.partial(self.setAudio, row=rowPosition,audio_channel="right"))
#self.table.setCellWidget(rowPosition,self.table.columnCount()-1,button_layout) #button_layout.addWidget(right_button)
cellWidget = QtGui.QWidget() cellWidget = QtGui.QWidget()
cellWidget.setLayout(button_layout) cellWidget.setLayout(button_layout)
#button_col=self.table.columnCount()-1
button_col=3 button_col=3
self.table.setCellWidget(rowPosition,button_col,cellWidget) self.table.setCellWidget(rowPosition,button_col,cellWidget)
def display_data(self, event): def display_data(self, event):
@ -1897,7 +1897,9 @@ class rds_parser_table_qt_Widget(QtGui.QWidget):
item.setText(quality_string) item.setText(quality_string)
if event.has_key('PTY'): if event.has_key('PTY'):
item=self.table.cellWidget(row,self.colorder.index('PTY')) item=self.table.cellWidget(row,self.colorder.index('PTY'))
tt=item.toolTip()
item.setText(event['PTY']) item.setText(event['PTY'])
item.setToolTip(tt)
if event.has_key('flags'): if event.has_key('flags'):
item=self.table.cellWidget(row,self.colorder.index('PTY')) item=self.table.cellWidget(row,self.colorder.index('PTY'))
item.setToolTip(Qt.QString(event['flags'])) item.setToolTip(Qt.QString(event['flags']))

Loading…
Cancel
Save