Просмотр банковских выписок

Java (11), Swing (Single document interface)

Мой знакомый получает банковские выписки в текстовом формате, где каждое поле задаётся парой "ключ-значение". Эти файлы он загружает в информационную систему. Иногда возникают проблемы: то дата платежа в выписке указана в странном формате, то вместо ИНН загружается ОКАТО, а то и вовсе нужного поля в файле нет. При просмотре файла в текстовом редакторе можно найти причину любой проблемы, но это очень неудобно. Было бы гораздо удобнее открыть файл в программе и увидеть банковскую выписку в виде таблицы, где каждая строка представляет собой отдельный платёж. Сразу будет видно, какие там платежи, от кого, кому, какие значения записаны в каждой колонке таблицы.

Именно это и делает данная программа. Но кроме того, она позволяет понять, как из немного Java и немного Swing сделать: меню, инструментальную панель, строку состояния, контекстное меню, диалог открытия файла, отображение файла в виде таблицы, поиск, Drag & Drop, использование L&F и собрать всё это вместе в виде SDI.

Для разработки использовался Eclipse. Проект расположен здесь: https://github.com/weekend-game/bankviewer/ (EN) и здесь: https://gitflic.ru/project/weekend-game/bankviewer/ (RU).

Как запустить программу

Скачайте репозиторий на свой компьютер. Всё необходимое для работы программы расположено в папке app. Зайдите в папку app и запустите программу двойным кликом по BankViewer.jar или, если она не запускается, двойным кликом по BankViewer.bat. Если и последнее не запускает программу, то скачайте и установите Java 11 или новее и снова попробуйте способы, описанные выше.

Как открыть проект в Eclipse

В Eclipse, в меню выберите File – Import... В появившемся окне выберите Existing Projects into Workspace. Укажите папку скачанного вами репозитория и нажмите кнопку Finish. Проект откроется в Eclipse. В Package Explorer (в левой части экрана) дважды кликните на файле BankViewer.java. Файл откроется для редактирования (в центральной части экрана). Запустите программу на выполнение, нажав Ctrl+F11 или так, как вам удобно запускать программы в Eclipse.

В проекте есть самостоятельная программа TestGenerator. Она находится в пакете game.weekend.bankviewer.util. В тексте программы можно указать имя файла и количество строк банковской выписки, и она сгенерирует тестовый файл. Файл Выписка1.txt был сгенерирован именно посредством TestGenerator.

Как работать с программой

Программа реализует Single Document Interface. Это значит, что после запуска мы видим привычное меню, инструментальную панель (тулбар), пустое пространство в центре окна для отображения документа и в самом низу окна - строку состояния.

Открыть банковскую выписку для просмотра можно тремя способами.

Первый способ - в меню выберите "Файл" - "Открыть..." или кнопкой на инструментальной панели. При этом откроется диалоговое окно, посредством которого надо будет указать файл банковской выписки, например, файл Выписка1.txt, который есть в репозитории.

Второй способ - воспользоваться Drag and Drop, а именно перетащить файл с банковской выпиской в центральную часть окна приложения.

Третий способ подходит для файлов, которые уже были открыты ранее. Пути к нескольким последним открытым файлам отображаются в меню "Файл". Достаточно выбрать нужный файл, и он будет отображен.

Для поиска текста в банковской выписке нажмите Ctrl+F, кнопку с изображением «бинокля» на панели инструментов или выберите из меню "Правка" пункт "Поиск...". В появившемся диалоговом окне укажите строку поиска, отметьте, следует ли учитывать регистр, укажите направление поиска и нажмите кнопку "Найти далее". Поиск можно продолжить из открытого окна поиска, с помощью кнопок тулбара или "горячих" клавиш (Ctrl+G или Ctrl+Shift+G).

Некоторые операции можно выполнить, нажав правую кнопку мыши, после чего отобразится контекстное меню.

Внешний вид приложения можно настроить с помощью пунктов меню "Вид".

Во-первых, можно выбрать предпочитаемый Look and Feel. Во-вторых, можно отключить отображение инструментальной панели и строки состояния. Банковскую выписку можно смотреть, пользуясь только «горячими» клавишами и пунктами меню, а вот место инструментальная панель и строка состояния занимают. В-третьих, можно выбрать язык пользовательского интерфейса: русский или английский.

Все настройки, и даже строка для поиска, сохраняются между сеансами работы.

Как программа написана

Главным классом приложения является класс BankViewer. Именно он содержит статический метод main() для запуска программы. В его конструкторе создаётся всё необходимое для работы.

Прежде всего, вызывается метод Proper.read(). Proper - это класс, который нужен, чтобы приложение могло сохранять данные между сеансами работы. Так сохраняются расположение и размер главного окна, предпочитаемый язык интерфейса, пути к нескольким недавно открытым файлам, признак того, надо ли отображать инструментальную панель и строку состояния, запоминается последняя введённая строка для поиска и некоторые другие данные. Метод read() читает файл с ранее записанными данными. Метод save() делает обратное: записывает всё, что запомнено в объекте, в файл. Метод setProperty(name, value) сохраняет значение value с именем "name". Метод getProperty(name, def) читает значение с именем "name"", а если оно не записывалось, то будет возвращено значение def. Для записи и восстановления расположения и размеров окна приложения используется пара методов saveBounds() и setBounds().

Затем статическим методом Loc.setLanguage() устанавливается язык интерфейса. Класс Loc отвечает за I18n. Работает это так: все строки, которые предназначены для отображения, написаны на английском языке с использованием нижнего подчеркивания вместо пробела. Метод Loc.get(строка) будет возвращать строки на ранее установленном языке, если, конечно, найдется файл локализации messages_xx.properties, где xx - условное обозначение языка. Иначе, в английской фразе подчёркивания будут заменены на пробел, а первая буква будет сделана прописной. И получившееся будет использовано для отображения. Для целей данной программы этого вполне достаточно.

Создаётся окно приложения - объект класса JFrame. И сразу вызывается метод makeJFrame(), в котором создаётся всё необходимое. Главное - это менеджер расположения BorderLayout(). Именно он поможет реализации SDI. В центральной части будет расположена JEditorPane для отображения банковской выписки в виде таблицы. В верхней части будет расположена инструментальная панель, в нижней части - строка состояния.

Затем я инициализирую класс Mes, предназначенный для отображения различных сообщений с помощью диалоговых окон. Методы Mes статические, и это создаёт некоторую связанность классов моих программ, но я отношусь к нему как к System.out в Java.

Создаётся панель класса JEditorPane для отображения банковской выписки в виде таблицы. И сразу вызывается метод makeJEditorPane(). В этом методе панель оборачивается в JScrollPane, размещается в центральной части окна приложения, отслеживает выделение/сброс выделения текста отображённой выписки, реализуется открытие файлов методом Drag and Drop.

Программа открывает файлы, чтобы отобразить их в табличном виде. Swing предоставляет готовое окно для указания файла, который надо открыть: это класс javax.swing.JFileChooser. Класс Filer - это только оболочка вокруг него, позволяющая слегка поднастроить внешний вид и поведение.

Для работы Filer необходим объект класса LastFiles. LastFiles при помощи класса Proper хранит и умеет читать при запуске программы несколько особенных строк - это пути к последним открытым файлам. Очень удобно увидеть их в меню «Файл» и быстро указать нужный вместо использования окна открытия файла. Filer же при каждом успешном открытии файла сохраняет путь к нему в объекте класса LastFiles. При неудачном открытии он удаляет такой путь из сохранённого списка, если таковой имеется, конечно. Для этих действий LastFiles предоставляет методы put() и remove(). Кроме этого, имеется метод getList(), при помощи которого Act из списка путей формирует фрагмент меню «Файл» со списком из последних открытых файлов.

Какая Java-программа не позволяет пользователю установить Look & Fill? Эта программа не является исключением. В меню «Вид» пользователь может выбрать любой доступный в его системе Look & Fill. Работать с этим помогает класс LaF.

Приложение содержит меню, инструментальную панель, к JEditorPane подключено контекстное меню . Все эти три объекта создаются методами класса Act. Каждый пункт меню или кнопка инструментальной панели - это объект класса Action. Все необходимые Action создаются методами класса Act. Именно поэтому это, наверное, самый большой по числу строк класс в этой программе. Но, наверное, это и самый простой класс в этой программе, потому что все Action создаются одинаково, а меню и инструментальная панель - это всего лишь перечисление нужных Action в нужном порядке. Впрочем, есть мелкие нюансы, которые легко понять, просматривая текст класса.

Строка состояния - это объект класса StatusBar. Собственно, строка состояния - это JPanel, в которой последовательно расположены три JTextField. В классе есть три метода для выдачи строкового сообщения в соответствующий JTextField. Крайне правое поле несколько особенное: сообщение, отображаемое в нём, будет видно в течение 5 секунд, а затем оно исчезает. Конечно, строку состояния можно бесконечно усложнять и улучшать, но для этой программы такой строки состояния вполне достаточно.

Для отображения информации в виде таблицы Swing предоставляет класс JTable. Но есть ещё один способ: JEditorPane, которому методом setPage(URL u) передали URL HTML-файла, в котором тегами <table> ... </table> сформирована таблица. Использую второй вариант. Итак, главное в программе - это преобразовать исходный текстовый файл «ключ-значение» в HTML-файл. Затем HTML-файл передаётся для отображения той самой JeditorPane, что расположена в центральной части главного окна приложения. Всё остальное - это реализация SDI и обеспечение удобства использования программы.

Если пользователь указал файл, то Filer в методе open() вызовет единственный публичный метод convert() класса Convertor. Этот метод конвертирует исходный файл с данными в виде пар ключ-значение в HTML-файл с теми же данными, представленными в виде таблицы. Затем этот HTML-файл будет передан JEditorPane, которая сама его разберет и отобразит без всякого вмешательства со стороны программиста.

Для реализации поиска в отображенном файле был создан класс Finder. FinderFrame - это окно для указания строки поиска, представляющее собой набор компонентов javax.swing. Алгоритм поиска реализован в классе Finder. При создании FinderFrame возникла задача размещения компонентов, и для её решения был создан класс GBL. GBL - это упрощение менеджера расположения GridBagLayout, адаптированное под нужды приложения.

Более подробно о работе программы можно узнать, скачав проект, открыв его в Eclipse, читая тексты классов, внося изменения, запуская программу и наблюдая, что из этого получается.

Итоги

Программа оказалась на удивление простой и полезной.

Хорошо бы…

Хорошо бы сделать изменение размера шрифта отображаемой банковской выписки.