Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Allow image on canvas to be coiped to the clipboard
  • Loading branch information
pshriwise committed Mar 6, 2026
commit d8905703e42edcfeeb63b4d61086341493d00670
15 changes: 15 additions & 0 deletions openmc_plotter/main_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,12 @@ def createMenuBar(self):
save_image_connector = partial(self.saveImage, filename=None)
self.saveImageAction.triggered.connect(save_image_connector)

self.copyImageAction = QAction("&Copy Image", self)
self.copyImageAction.setShortcut("Ctrl+Shift+C")
self.copyImageAction.setToolTip('Copy plot image to clipboard')
self.copyImageAction.setStatusTip('Copy plot image to clipboard')
self.copyImageAction.triggered.connect(self.copyImageToClipboard)

self.saveViewAction = QAction("Save &View...", self)
self.saveViewAction.setShortcut(QtGui.QKeySequence.Save)
self.saveViewAction.setStatusTip('Save current view settings')
Expand Down Expand Up @@ -199,6 +205,7 @@ def createMenuBar(self):

self.fileMenu = self.mainMenu.addMenu('&File')
self.fileMenu.addAction(self.reloadModelAction)
self.fileMenu.addAction(self.copyImageAction)
self.fileMenu.addAction(self.saveImageAction)
self.fileMenu.addAction(self.exportDataAction)
self.fileMenu.addSeparator()
Expand Down Expand Up @@ -519,6 +526,14 @@ def saveImage(self, filename=None):
self.plotIm.saveImage(filename)
self.statusBar().showMessage('Plot Image Saved', 5000)

def copyImageToClipboard(self):
if self.plotIm.copyImageToClipboard():
self.statusBar().showMessage('Plot Image Copied', 5000)
return True

self.statusBar().showMessage('No Plot Image Available', 5000)
return False

def saveView(self):
filename, ext = QFileDialog.getSaveFileName(self,
"Save View Settings",
Expand Down
19 changes: 19 additions & 0 deletions openmc_plotter/plotgui.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,24 @@ def saveImage(self, filename):
filename += ".png"
self.figure.savefig(filename, transparent=True)

def copyImageToClipboard(self):
"""Copy the current canvas image to the clipboard."""
self.draw()
width, height = self.get_width_height()
if width <= 0 or height <= 0:
return False

image = QtGui.QImage(self.buffer_rgba(),
width,
height,
QtGui.QImage.Format_RGBA8888).copy()
pixmap = QtGui.QPixmap.fromImage(image)
if pixmap.isNull():
return False

QtGui.QGuiApplication.clipboard().setPixmap(pixmap)
return True

def getDataIndices(self, event):
cv = self.model.currentView

Expand Down Expand Up @@ -506,6 +524,7 @@ def contextMenuEvent(self, event):
olapColorAction.triggered.connect(connector)

self.menu.addSeparator()
self.menu.addAction(self.main_window.copyImageAction)
self.menu.addAction(self.main_window.saveImageAction)
self.menu.addAction(self.main_window.saveViewAction)
self.menu.addAction(self.main_window.openAction)
Expand Down
31 changes: 31 additions & 0 deletions tests/setup_test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import shutil

import pytest
from PySide6 import QtGui, QtWidgets

from openmc_plotter.main_window import MainWindow, _openmcReload

Expand Down Expand Up @@ -56,3 +57,33 @@ def test_batch_image(tmpdir, qtbot):
filecmp.cmp(orig / 'ref1.png', tmpdir / 'test1.png')

mw.close()

def test_copy_image_to_clipboard(tmpdir, monkeypatch):
orig = tmpdir.chdir()
QtWidgets.QApplication.instance() or QtWidgets.QApplication([])
mw = MainWindow(model_path=orig)
_openmcReload(model_path=orig)
mw.loadGui()

class FakeClipboard:
def __init__(self):
self.pixmap = None

def setPixmap(self, pixmap):
self.pixmap = pixmap

fake_clipboard = FakeClipboard()
monkeypatch.setattr(QtGui.QGuiApplication,
'clipboard',
staticmethod(lambda: fake_clipboard))

try:
assert mw.waitForPlotIdle(60000)
assert mw.copyImageToClipboard()
finally:
orig.chdir()

assert fake_clipboard.pixmap is not None
assert not fake_clipboard.pixmap.isNull()

mw.close()