Skip to content

Instantly share code, notes, and snippets.

@Meatplowz
Last active March 9, 2023 01:36
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Meatplowz/1e99b987ee8caac4bafe6ec298dc6203 to your computer and use it in GitHub Desktop.
Save Meatplowz/1e99b987ee8caac4bafe6ec298dc6203 to your computer and use it in GitHub Desktop.
Convert a designer .UI file to .Py file and insert into an existing .Py tool file
import os
from shutil import copyfile
try:
# Pyside
from pysideuic import compileUi
except:
# Pyside2
from pyside2uic import compileUi
def update_py_ui(ui_py, tool_py):
"""
Inject the modified .ui/.py code and inject into the actual python tool
*Arguments:*
* ``ui_py`` The .py file converted from .ui
* ``tool_py`` The .py file that will we inject the updated ui code into
*Keyword Arguments:*
* ``None``
*Returns:*
* ``None``
*Author:*
* randall.hess, randall.hess@gmail.com, 09/02/2018 3:41:59 PM
"""
# open the ui_py file
try:
ui_file = open(ui_py, 'r')
except:
return
ui_all_lines = ui_file.readlines()
ui_file.close()
# scan to the line after class.startswith
ui_lines = None
for index in range(len(ui_all_lines)):
line = ui_all_lines[index].lstrip()
if line.startswith('class'):
ui_lines = ui_all_lines[index+1:]
break
# make sure we have ui lines
if not ui_lines:
return
# remove any from/import lines
# when promoting to external classes from/import lines are added
ui_lines = [line for line in ui_lines if not 'from' in line and not 'import' in line]
# open the tool_py file
try:
tool_file = open(tool_py, 'r')
except:
# file does not exist to read
return
tool_all_lines = tool_file.readlines()
tool_file.close()
# backup the tool file
name_split = os.path.basename(tool_py).split(os.path.extsep)
backup_name = name_split[0] + '_bak' + os.path.extsep + name_split[1]
backup_tool_py = os.path.join(os.path.dirname(tool_py), backup_name)
# remove def setupUI() lines through end of def retranslateUI() > def/class = 2 empty new lines
start_replace_index = None
end_replace_index = None
end_replace_scan = False
empty_line_range = 2 # Following PEP8 2 empty lines
empty_line_count = 0
for index in range(len(tool_all_lines)):
line = tool_all_lines[index].lstrip()
if start_replace_index is None:
if line.startswith('def setupUi'):
start_replace_index = index
continue
else:
if not end_replace_scan:
# start scanning for the end of this def
if line.startswith('def retranslateUi'):
end_replace_scan = True
continue
else:
# scan for a new def/class line or stop after two empty lines
strip_line = line.rstrip()
if not strip_line:
empty_line_count += 1
# exit end scan if we hit too many empty lines
if empty_line_count == empty_line_range:
end_replace_index = index
break
else:
# reset empty count if we continue to find text in subsequent lines
empty_line_count = 0
# exit if the next def line is found
if strip_line.startswith('def'):
end_replace_index = index-1
break
# exit if the new class line is found
elif strip_line.startswith('class'):
end_replace_index = index-1
break
# make sure we have both indices
if not start_replace_index is None and not end_replace_index is None:
# lines that we keep up until we replace
start_lines = tool_all_lines[0:start_replace_index]
# lines that we keep after we are replacing
end_lines = tool_all_lines[end_replace_index:]
# create new tool lines
new_tool_lines = start_lines
new_tool_lines.extend(ui_lines)
new_tool_lines.extend(end_lines)
updated_file = False
with open(backup_tool_py, "w") as backup_tool_file:
backup_tool_file.writelines(new_tool_lines)
updated_file = True
# make sure the file was written properly
if updated_file:
# make sure file is writable and copy over it
try:
os.chmod(tool_py, 0777)
copyfile(backup_tool_py, tool_py)
except:
pass
def convert_qt_py(ui_py_file):
"""
Manual conversion of the python ui file to work with Qt.py
A couple search and replace strings have done the trick so far.
# Alternatively, you can use the conversion for Qt.py specifically
https://github.com/mottosso/Qt.py/issues/131
*Arguments:*
* ``ui_py_file`` The .py file that was converted from the .ui
*Keyword Arguments:*
* ``None``
*Returns:*
* ``None``
*Author:*
* randall.hess, randall.hess@gmail.com, 09/02/2018 3:41:59 PM
"""
# need to replace strings in this order
replace_strings = { 1: ['QtGui.QApplication','QtWidgets.QApplication']
,2: ['QtGui','QtWidgets']
,3: ['QtWidgets.QFont','QtGui.QFont']
}
# ignore lines with any of these strings found in them
ignore_line_strings = ['import']
if os.path.exists( ui_py_file ):
lines = None
try:
file_ = open( ui_py_file, 'r' )
lines = file_.readlines()
file_.close()
except:
cmds.warning('Could not open the ui python file!')
return
if lines:
new_lines = []
for line in lines:
new_line = line
# check for lines to ignore
if not any([x in new_line for x in ignore_line_strings]):
# see if there are strings to replace in this line
for index, replace_tuple in sorted(replace_strings.iteritems()):
old_str, new_str = replace_tuple
if old_str in new_line:
while old_str in new_line:
new_line = new_line.replace(old_str, new_str)
# add the modified/unmodified line
new_lines.append(new_line)
else:
new_lines.append(new_line)
# write all the new lines to the same file
with open(ui_py_file, 'w') as _file:
_file.writelines(new_lines)
def convert_ui_to_py( ui_file, tool_file):
"""
Main method to convert a ui file to python
Update the actual python tool file with new code
*Arguments:*
* ``ui_file`` The .ui file we are converting
* ``tool_file`` The .py file that will we inject the updated ui code into
*Keyword Arguments:*
* ``None``
*Returns:*
* ``None``
*Author:*
* randall.hess, randall.hess@gmail.com, 09/02/2018 3:41:59 PM
"""
# check the incoming files
files = [ui_file, tool_file]
for _file in files:
if _file is None:
return
if not os.path.lexists(_file):
return
# python file and ui file should be named the same
py_filename = ui_file.replace('.ui','.py')
# create a temp .py file that we convert the .ui file into
py_file = open(py_filename, 'w')
# convert the .ui file to the .py file
compileUi(ui_file, py_file, False, 4, False)
py_file.close()
# handle conversion for Qt.py
# This is optional only if you intend to run ui code with Qt.py
convert_qt_py(py_filename)
# update the actual python tool
update_py_ui(py_filename, tool_file)
# Example
ui_file = r'D:\temp.ui'
tool_file = r'D:\test_dialog.py'
convert_ui_to_py(ui_file, tool_file)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment