Summary: Finally, my solution used the Kivy framework. Kivy is a graphical framework for Python and, critically for my app, has the ability to output to both the RPi's LCD touchscreen and HDMI. Kivy can do a lot of UI heavy lifting, I was able to construct a rich control panel on the LCD touchscreen which served as a great front end for the machine.
Try the following steps, to get a very basic demo:
Put Kivy on the Pi. The simplest way to is to use a KivyPie image to start with a clean, lightweight distribution with Kivy already setup.
Create these 2 files in the same directory and run "dualoutput_main.py":
dualoutput_main.py
# Using Kivy Framework, this example module provides a basic touchscreen interface
# on official RasPi 3 touchscreen.
# A button press runs a separate python app (dualoutput_sub.py)
# which is configured to run through RasPi HMDI output.
# It is important to note that both instances are unconnected - this is an undesirable
# sideffect of trying to get 2 different results on 2 different outputs on the RasPi 3.
# Comms between the two instances, if needed, is a separate topic ;-)
from kivy.config import Config
Config.set('graphics', 'width', '800')
Config.set('graphics', 'height', '440')
import os
os.environ["KIVY_BCM_DISPMANX_ID"] = "4" #LCD
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
import subprocess
Builder.load_string("""
<TouchScreen>:
BoxLayout:
orientation: 'vertical'
padding: 30
spacing: 30
Label:
text: 'Click button to run HDMI app'
Button:
text: 'Run HDMI output'
on_release: root.hdmi_go()
""")
class TouchScreen(Screen):
def hdmi_go(self):
print 'opening projector sequence'
subprocess.Popen("python dualoutput_sub.py", stdout=subprocess.PIPE, shell=True)
runTouchApp(TouchScreen())
dualoutput_sub.py
# Example app to demonstrate kivy output on RasPi 3 HDMI
# Simple label counter ticks up to infinity
import os
os.environ["KIVY_BCM_DISPMANX_ID"] = "5" #HDMI
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.base import runTouchApp
from kivy.clock import Clock
from kivy.properties import NumericProperty # @UnresolvedImport (for Eclipse users)
Builder.load_string("""
<HDMITestScreen>:
Label:
font_size: 50
text: str(root.label_number)
""")
class HDMITestScreen(Screen):
label_number = NumericProperty(0)
def __init__(self, **kwargs):
super(HDMITestScreen, self).__init__(**kwargs)
Clock.schedule_interval(self.increment_label_number, 1)
def increment_label_number(self, dt):
self.label_number += 1
runTouchApp(HDMITestScreen())
Notes:
- KivyPie was a useful lightweight distribution for dev.
- I ran the LCD instance as the main program, which called a subprocess for a separate HDMI instance.
- Learning Python (coming from Java) and I found this site useful.
- Learning Kivy is hard but worth learning, start here.
- As a noob, all this tricky, but the results were definitely worth it (Kivy is very powerful for this kind of UI) and I will use this approach for future machines.
- I have yet to find a better solution!