電子カルテ

当院では,電子カルテとして,オープンソースの OpenDolphin 1.3.0(デジタルグローブ社)を使用させていただいています。素晴らしいソフトをオープンソースで公開されているデジタルグローブ社には,とても感謝しています。

 どんな素晴らしい電子カルテも,実際に運用するには個々の医院に合わせたカスタマイズが必要だと思います。その場合,オープンソースなら,自院のためだけに自由にカスタマイズすることができます。このブログでは,OpenDolphin を当院で運用するにあたって,色々カスタマイズした内容を公開しています。


  • カスタマイズしたソースは公開しています
  • デジタルグローブ社はライフサイエンスコンピューティング(株)と合併し,現在同社のオープンドルフィンラボとなっています
  • 本家オープンドルフィンラボの OpenDolphin は既に ver. 2.x になっています

2017年1月15日 (日)

BasicInfoInspecter の表示

BasicInfoInspecter でカナ名も出すことにした。名前が長いと欠けてしまうので,deriveFont で無理矢理詰め込む処理を組み込んだ。

Jugem

// 名前が長い場合は,カナ名を圧縮する
if (kanjiName.length() + kanaName.length() > 15) {
  float sy = (float) (15.5 - kanjiName.length()) / kanaName.length();
  Font font = nameLabel.getFont().deriveFont(AffineTransform.getScaleInstance(sy, 1));
  kanaLabel.setFont(font);
}

2017年1月14日 (土)

フォーカス処理の見直し

文書入力の際に,フォーカス処理はとても重要で,ウインドウが開いたらすぐに必要な場所に入力できないとかなりストレスがたまる。今まで,気がついたときに色々フォーカス処理()を加えてきたのだが,行き当たりばったりで組み込んできたので,どこでどのようなフォーカス処理をしているのか把握できなくなってしまっていた。フォーカスの取り合い?かもしれない動作が見られるようにもなっていたので,フォーカス処理を全部見直しすることにした。フォーカスは Focuser というクラスを使って,必ずここにフォーカス請求するようにリファクタリングした。案の定,不要なフォーカス請求をかなり入れてしまっていることが判明して,すっきりさせることができた。
package open.dolphin.ui;

import java.awt.Component;
import java.awt.KeyboardFocusManager;
import javax.swing.SwingUtilities;
import org.apache.log4j.Logger;

public class Focuser {
    private static final Logger logger = Logger.getLogger(Focuser.class);
    private static Component component;

    public static void requestFocus(Component c) {
        component = c;
        KeyboardFocusManager.getCurrentKeyboardFocusManager().clearGlobalFocusOwner();
        SwingUtilities.invokeLater(Focuser::request);
    }

    private static void request() {
        boolean result = component.requestFocusInWindow();
        logger.info(component.getClass().toString() + ": request focus " + ((result)? "succeeded" : "failed"));
    }
}

2017年1月13日 (金)

JTextComponent の undo

オリジナルでは KartePane のみ ChartMediator 内で undo 機能が付けられていたが,JTextComponentUndoManager を作って undo 機能を独立させ,MemoInspector,TextStampEditor にも undo 機能を付けた。
package open.dolphin.helper;

import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.event.UndoableEditEvent;
import javax.swing.text.JTextComponent;
import javax.swing.undo.UndoManager;

/**
 * JTextComponent に Undo 機能を付ける.<br>
 * 使用例:
 * <pre>{@code
 * TextComponentUndoManager manager = new TextComponentUndoManager();
 * JTextPane textComponent = new JTextPane();
 * manager.addUndoActionTo(textComponent);
 * textComponent.getDocument().addUndoableEditListener(manager::listener);
 * }</pre>
 * @author pns
 */
public class TextComponentUndoManager extends UndoManager {
    private static final long serialVersionUID = 1L;

    private Action undoAction;
    private Action redoAction;

    public TextComponentUndoManager() {
        // default undo action
        undoAction = new AbstractAction("undo") {
            private static final long serialVersionUID = 1L;
            @Override
            public void actionPerformed(ActionEvent e) {
                undo();
            }
        };
        // default redo action
        redoAction = new AbstractAction("redo") {
            private static final long serialVersionUID = 1L;
            @Override
            public void actionPerformed(ActionEvent e) {
                redo();
            }
        };
    }

    /**
     * JTextComponent に Undo 機能を付ける utility static method.
     * @param c
     * @return
     */
    public static TextComponentUndoManager getManager(JTextComponent c) {
        TextComponentUndoManager manager = new TextComponentUndoManager();
        manager.addUndoActionTo(c);
        c.getDocument().addUndoableEditListener(manager::listener);
        return manager;
    }

    public void addUndoActionTo(JTextComponent c) {
        ActionMap am = c.getActionMap();
        InputMap im = c.getInputMap();
        am.put("undo", undoAction);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK), "undo");
        am.put("redo", redoAction);
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.META_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK), "redo");
    }

    public void setUndoAction(Action action) {
        undoAction = action;
    }

    public void setRedoAction(Action action) {
        redoAction = action;
    }

    public void listener (UndoableEditEvent e) {
        addEdit(e.getEdit());
        updateActionStatus(); // 文字入力毎に action が enable/disable される
    }

    @Override
    public void undo() {
        if (canUndo()) { super.undo(); }
        updateActionStatus();
    }

    @Override
    public void redo() {
        if (canRedo()) { super.redo(); }
        updateActionStatus();
    }

    private void updateActionStatus() {
        undoAction.setEnabled(canUndo());
        redoAction.setEnabled(canRedo());
    }
}

2017年1月 6日 (金)

インスペクタのデザイン

インスペクタ部分のデザインを微調整して,全体に連続感が出るようにした。
さらに,関連文書がある場合 Badge で関連文書数を表示するようにした。(右が新しい画面)

Inspector

2017年1月 5日 (木)

待ち人数のバッジ表示

待ち人数をバッジ表示するようにしてみた。患者検索で作業中の時に患者さんが来ても,受付リストボタンにバッジが表示されるので受付されたことが分かる。

Badge_3

PNSBadgeTabbedPane.java

2016年12月16日 (金)

ウインドウのデザイン変更

JavaFX では,Stage.UNIFIED でタイトルバーと内容が連続したウインドウを作ることができる。

Dolphin2

これを Swing でもできないかとずっと悩んでいたのだが,先日ふと見た Web ページで,JFrame に
getRootPane().putClientProperty("apple.awt.brushMetalLook", Boolean.TRUE);
とするとできることが分かった。早速,これを使ってデザインを変更した。上が変更前,下が変更後。

Dolphin

コマンドボタン等をのせるパネル (HorizontalPanel) の背景色を Window activate/deactivate に合わせて変えて,タイトルバーと連続するようにしたのだが,アプリケーション切り替えのタイミングによっては,バックグランドに回っているのに Window activate のイベントが送られてくることがあった。そうなると,タイトルバーは inactive なのに,それに連続するパネルが active になっているという間抜けな状態になる。

Fail

試行錯誤の結果,com.apple.eawt.AppEventListener を使って無理矢理ごまかした。
追記
quaqua を外すと,window active / deactive 時のパネルの色変更を aqua laf 側でしてくれることが判明したため,quaqua の PanelUI を exclude した。これで, AppForegroundListener を使った workaround は不要になった。しかし,quaqua の PanelUI は TitledBorder の表示もしていたため,自前で TitledBorder を作って対応した。また,JOptionPane の container のバックグランドが黒になってしまうことも判明して対応した。

2016年12月11日 (日)

ダブルクリックでスタンプ入力2

スタンプ箱からダブルクリックでスタンプを入力する方法がかなり気に入ったので,他のカルテのスタンプも入力できるようにした。
  • static 変数 "ChartImpl.allCharts","EditorFrame.allEditorFrames" の List に,ウインドウが activate された順番を保持するようにした。つまり,List の先頭をとると一番手前のウインドウが取れるようにした。
  • これを利用して,ダブルクリックで,一番手前のウインドウにスタンプが挿入されるようにした。スタンプ箱のスタンプと,Viewer のカルテのスタンプをダブルクリックすると,DiagnosisDocument あるいは入力中の EditorFrame にスタンプが入力される。
  • ダブルクリックしてからドラッグしてしまうと,スタンプが両方のイベントを受けてしまうので,ダブルクリック後 50 ms 以内にマウスが動いたら,ダブルクリックのイベントはキャンセルするようにした。
  • 編集中の EditorFrame のスタンプをダブルクリックした場合は,これまで通りスタンプエディタが立ち上がる。
  • 病名入力の場合は,「左右」「の疑い」などの修飾語を,ダブルクリック入力直後にショートカットで入力できるようにした。これまでは「ドラッグ&ドロップ→病名選択→ショートカットキー」だったのが,「ダブルクリック→ショートカットキー」で入力できるようになった。
自分だけ使うなら,こんな変な入力方法に改造してもOK。(変更部分まとめ

2016年11月30日 (水)

スタンプをダブルクリックで入力

前回の改造で,スタンプ箱ポップアップからカルテに病名入力できるようにしていたが,結構便利だったので,処方など他のスタンプもポップアップで入力できるようにした。
 さらに,スタンプのダブルクリックでも入力できるようにした。開いているカルテが1つだけならばダブルクリックで直接入力,開いているカルテが2つ以上ある場合は,右クリックと同じポップアップが表示されるようにした。また一つ横着になってしまった。

2016年7月 9日 (土)

プリンタ更新

処方箋を印刷していた HL-5450DN が,印刷後に用紙の角がカールするようになったり,文字がにじんでしまったりするようになっていた。何とか使えるレベルではあったが,さらに,時々紙送りに失敗してエラーを出して止まってしまうようになったため,そろそろ限界と考えて,新しいプリンタを買った。ページカウントは 54,578。

当院の初代プリンタ HL-5250DN は14万ページの名機だったが,2代目の HL-5450DN は1台目は9万ページ,今回の2台目は5万ページでの交代となった。既に HL-5450DN は廃番になっていたため,3代目プリンタとして HL-L5100DN を購入した。30万ページの高耐久性をうたっているが,どれくらいがんばってくれるか楽しみである。

Photo 2 3
初代 (HL-5250DN) 2代目 (HL-5450DN) 3代目 (HL-L5100DN)
2008年〜2013年 2013年〜2016年 2016年〜

2016年7月 8日 (金)

スタンプ箱ポップアップから病名入力

スタンプ箱の傷病名ツリーのポップアップから病名入力できるようにした。病名を選択してポップアップすると,その時に開いているカルテの一覧が表示され,そのカルテに選択した病名を送ることができる。病名入力の際に,ドラッグ移動距離を大幅に減らすことができた。

Popup

«診療中に ORCA の印刷止まる