KDP(電子出版)のメモ 急急如律令

Amazon Kindleダイレクト・パブリッシングでの電子出版や電子書籍の作成販売について、文章やイラストの作成や編集方法について書いています。

下記のコードをAndroidのpreferenceに書き換えて 表紙と画像部分

設定をカテゴリーごとに分割 developer.android.com

あなた:

下記のコードをAndroidのpreferenceに書き換えて

     ////////////////////////////////////////////////////////////////
        //Tab 変換
        ////////////////////////////////////////////////////////////////

        tabPanel = new JPanel();
        tabPanel.setLayout(new BoxLayout(tabPanel, BoxLayout.Y_AXIS));
        jTabbedPane.setPreferredSize(new Dimension(1920, 220));
        jTabbedPane.addTab("変換 ", epubIcon, tabPanel);

        ////////////////////////////////
        //表題
        ////////////////////////////////
        panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
        panel.setMinimumSize(panelSize);
        panel.setMaximumSize(panelSize);
        panel.setPreferredSize(panelSize);
        panel.setBorder(padding4H2V);
        tabPanel.add(panel);
        label = new JLabel("表題: ");
        panel.add(label);
        label = new JLabel("本文内");
        label.setBorder(padding2H);
        panel.add(label);
        jComboTitle = new JComboBox<String>(BookInfo.TitleType.titleTypeNames);
        jComboTitle.setFocusable(false);
        jComboTitle.setMaximumSize(new Dimension(200, 22));
        jComboTitle.setBorder(padding0);
        ((JLabel)jComboTitle.getRenderer()).setBorder(padding2H);
        panel.add(jComboTitle);
        //入力ファイル名優先
        jCheckPubFirst = new JCheckBox("先頭が発行者");
        jCheckPubFirst.setFocusPainted(false);
        panel.add(jCheckPubFirst);
        //入力ファイル名優先
        panel.add(new JLabel("  "));
        jCheckUseFileName = new JCheckBox("ファイル名優先 ");
        jCheckUseFileName.setFocusPainted(false);
        panel.add(jCheckUseFileName);

        ////////////////////////////////
        //表紙
        ////////////////////////////////
        panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
        panel.setMinimumSize(panelSize);
        panel.setMaximumSize(panelSize);
        panel.setPreferredSize(panelSize);
        panel.setBorder(padding4H2V);
        tabPanel.add(panel);
        //表紙
        label = new JLabel("表紙: ");
        panel.add(label);

        jTextMaxCoverLine = new JTextField(10);
        jTextMaxCoverLine.setToolTipText("先頭の挿絵に利用する画像注記を取得する最大行数 0なら制限なし");
        jTextMaxCoverLine.setHorizontalAlignment(JTextField.RIGHT);
        jTextMaxCoverLine.setMinimumSize(text4);
        jTextMaxCoverLine.setMaximumSize(text4);
        jTextMaxCoverLine.setPreferredSize(text4);
        jTextMaxCoverLine.addFocusListener(new TextSelectFocusListener(jTextMaxCoverLine));
        jTextMaxCoverLine.setInputVerifier(new IntegerInputVerifier(10, 0, 9999));
        panel.add(jTextMaxCoverLine);
        jLabelMaxCoverLine = new JLabel("行目までの");
        jLabelMaxCoverLine.setToolTipText(jTextMaxCoverLine.getToolTipText());
        jLabelMaxCoverLine.setBorder(padding2H);
        panel.add(jLabelMaxCoverLine);

        jComboCover = new JComboBox<String>(new String[]{"[先頭の挿絵]", "[入力ファイル名と同じ画像(png,jpg)]", "[表紙無し]", "http://","[SVG表紙生成]"});
        jComboCover.setEditable(true);
        jComboCover.setPreferredSize(new Dimension(320, 24));
        jComboCover.addActionListener(arg0 -> {
            boolean visible = jComboCover.getSelectedIndex() == 0;
            jTextMaxCoverLine.setVisible(visible);
            jLabelMaxCoverLine.setVisible(visible);
        });
        panel.add(jComboCover);
        new DropTarget(jComboCover.getEditor().getEditorComponent(), DnDConstants.ACTION_COPY_OR_MOVE, new DropCoverListener(), true);
        boolean visible = jComboCover.getSelectedIndex() == 0;
        jTextMaxCoverLine.setVisible(visible);
        jLabelMaxCoverLine.setVisible(visible);

        jButtonCover = new JButton("選択");
        jButtonCover.setBorder(padding3);
        jButtonCover.setIcon(new ImageIcon(Objects.requireNonNull(AozoraEpub3Applet.class.getResource("images/cover.png"))));
        jButtonCover.setFocusPainted(false);
        jButtonCover.addActionListener(new CoverChooserListener(this));
        panel.add(jButtonCover);
        jCheckCoverHistory = new JCheckBox("表紙履歴利用", true);
        jCheckCoverHistory.setToolTipText("前回の変換(またはスキップ)で設定した表紙を利用します ※履歴は再起動時に初期化されます");
        jCheckCoverHistory.setFocusPainted(false);
        panel.add(jCheckCoverHistory);

        panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
        panel.setMinimumSize(panelSize);
        panel.setMaximumSize(panelSize);
        panel.setPreferredSize(panelSize);
        panel.setBorder(padding4H2V);
        tabPanel.add(panel);
        //ページ出力
        label = new JLabel("ページ出力:");
        panel.add(label);
        jCheckCoverPage = new JCheckBox("表紙画像 ", true);
        jCheckCoverPage.setFocusPainted(false);
        panel.add(jCheckCoverPage);
        //左右中央
        jCheckTitlePage = new JCheckBox("表題", true);
        jCheckTitlePage.setToolTipText("表題を単独のページで出力します。チェック無し時は表題等は出力されません");
        jCheckTitlePage.setFocusPainted(false);
        panel.add(jCheckTitlePage);
        label = new JLabel("(");
        panel.add(label);
        buttonGroup = new ButtonGroup();
        jRadioTitleNormal = new JRadioButton("本文内 ");
        jRadioTitleNormal.setToolTipText("別ページ処理せずに本文中に表題等を出力します。 目次は表題前に出力されます");
        jRadioTitleNormal.setBorder(padding0);
        jRadioTitleNormal.setIconTextGap(1);
        panel.add(jRadioTitleNormal);
        buttonGroup.add(jRadioTitleNormal);
        jRadioTitleMiddle = new JRadioButton("中央 ", true);
        jRadioTitleMiddle.setToolTipText("中央寄せの表題ページを出力します");
        jRadioTitleMiddle.setBorder(padding0);
        jRadioTitleMiddle.setIconTextGap(1);
        panel.add(jRadioTitleMiddle);
        buttonGroup.add(jRadioTitleMiddle);
        jRadioTitleHorizontal = new JRadioButton("横書き");
        jRadioTitleHorizontal.setToolTipText("横書きの表題ページを出力します");
        jRadioTitleHorizontal.setBorder(padding0);
        jRadioTitleHorizontal.setIconTextGap(1);
        panel.add(jRadioTitleHorizontal);
        buttonGroup.add(jRadioTitleHorizontal);
        label = new JLabel(") ");
        panel.add(label);
        jCheckTocPage = new JCheckBox("目次");
        jCheckTocPage.setToolTipText("目次ページを表題ページの次に追加します");
        jCheckTocPage.setFocusPainted(false);
        panel.add(jCheckTocPage);
        label = new JLabel("(");
        panel.add(label);
        buttonGroup = new ButtonGroup();
        jRadioTocV = new JRadioButton("縦 ", true);
        jRadioTocV.setFocusPainted(false);
        jRadioTocV.setIconTextGap(2);
        jRadioTocV.setBorder(padding0);
        panel.add(jRadioTocV);
        buttonGroup.add(jRadioTocV);
        jRadioTocH = new JRadioButton("横");
        jRadioTocH.setFocusPainted(false);
        jRadioTocH.setIconTextGap(2);
        jRadioTocH.setBorder(padding0);
        panel.add(jRadioTocH);
        buttonGroup.add(jRadioTocH);
        label = new JLabel(")");
        panel.add(label);

ChatGPT:

AndroidのPreference画面は、PreferenceFragmentCompatを使って構築するのが一般的です。Swingのように細かくレイアウトを組むのではなく、XMLで定義し、設定項目(CheckBoxPreference、EditTextPreference、ListPreferenceなど)で構成されます。

以下は、あなたのSwing UIをAndroidのPreferenceに書き換えた例です(要素を対応させたサンプル):

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 表題 -->
    <PreferenceCategory android:title="表題">
        <ListPreference
            android:key="title_type"
            android:title="表題の種類"
            android:entries="@array/title_type_names"
            android:entryValues="@array/title_type_values"
            android:defaultValue="default" />

        <CheckBoxPreference
            android:key="pub_first"
            android:title="先頭が発行者"
            android:defaultValue="false" />

        <CheckBoxPreference
            android:key="use_filename"
            android:title="ファイル名優先"
            android:defaultValue="false" />
    </PreferenceCategory>

    <!-- 表紙 -->
    <PreferenceCategory android:title="表紙">
        <EditTextPreference
            android:key="max_cover_lines"
            android:title="最大行数"
            android:dialogTitle="画像注記の取得最大行数"
            android:defaultValue="0"
            android:inputType="number" />

        <ListPreference
            android:key="cover_mode"
            android:title="表紙設定"
            android:entries="@array/cover_options"
            android:entryValues="@array/cover_options_values"
            android:defaultValue="0" />

        <CheckBoxPreference
            android:key="use_cover_history"
            android:title="表紙履歴利用"
            android:defaultValue="true"
            android:summary="前回の表紙を利用。履歴は再起動で初期化されます。" />
    </PreferenceCategory>

    <!-- ページ出力 -->
    <PreferenceCategory android:title="ページ出力">
        <CheckBoxPreference
            android:key="output_cover_page"
            android:title="表紙画像を出力"
            android:defaultValue="true" />

        <CheckBoxPreference
            android:key="output_title_page"
            android:title="表題ページを出力"
            android:defaultValue="true" />

        <ListPreference
            android:key="title_page_style"
            android:title="表題ページスタイル"
            android:entries="@array/title_page_styles"
            android:entryValues="@array/title_page_styles_values"
            android:defaultValue="middle" />

        <CheckBoxPreference
            android:key="output_toc"
            android:title="目次ページを出力"
            android:defaultValue="true" />

        <ListPreference
            android:key="toc_style"
            android:title="目次スタイル"
            android:entries="@array/toc_styles"
            android:entryValues="@array/toc_styles_values"
            android:defaultValue="vertical" />
    </PreferenceCategory>

</PreferenceScreen>
<resources>
    <string-array name="title_type_names">
        <item>本文内</item>
        <item>別ページ</item>
    </string-array>
    <string-array name="title_type_values">
        <item>inline</item>
        <item>separate</item>
    </string-array>

    <string-array name="cover_options">
        <item>先頭の挿絵</item>
        <item>ファイル名と同じ画像</item>
        <item>表紙無し</item>
        <item>http://</item>
        <item>SVG表紙生成</item>
    </string-array>
    <string-array name="cover_options_values">
        <item>0</item>
        <item>1</item>
        <item>2</item>
        <item>3</item>
        <item>4</item>
    </string-array>

    <string-array name="title_page_styles">
        <item>本文内</item>
        <item>中央</item>
        <item>横書き</item>
    </string-array>
    <string-array name="title_page_styles_values">
        <item>normal</item>
        <item>middle</item>
        <item>horizontal</item>
    </string-array>

    <string-array name="toc_styles">
        <item>縦</item>
        <item>横</item>
    </string-array>
    <string-array name="toc_styles_values">
        <item>vertical</item>
        <item>horizontal</item>
    </string-array>
</resources>
public class ConvertPreferenceFragment extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.pref_convert, rootKey);
    }
}

必要であれば、このUIに対してカスタムな動作(たとえば、ListPreferenceの選択肢によって他の要素の表示/非表示を切り替えるなど)をJava/Kotlinコードで追加できます。

続きの変換も必要であれば、教えてください!

あなた:

下記のコードをAndroidのpreferenceに書き換えて

    ////////////////////////////////
    //出力ファイル設定
    ////////////////////////////////
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setMinimumSize(panelSize);
    panel.setMaximumSize(panelSize);
    panel.setPreferredSize(panelSize);
    panel.setBorder(padding4H2V);
    tabPanel.add(panel);
    //拡張子
    label = new JLabel("拡張子: ");
    panel.add(label);
    jComboExt = new JComboBox<String>(new String[]{".epub", ".kepub.epub", ".fxl.kepub.epub", ".mobi", ".mobi+.epub"});
    jComboExt.setToolTipText("出力するファイルの拡張子を選択します。 mobi出力時はKindlegenが必要になります");
    jComboExt.setEditable(true);
    jComboExt.setMaximumSize(new Dimension(110, 24));
    jComboExt.setPreferredSize(new Dimension(110, 24));
    panel.add(jComboExt);
    label = new JLabel("  ");
    panel.add(label);
    //出力ファイル名設定
    jCheckAutoFileName = new JCheckBox("出力ファイル名に表題利用", true);
    jCheckAutoFileName.setFocusPainted(false);
    panel.add(jCheckAutoFileName);
    label = new JLabel("  ");
    panel.add(label);
    //ファイルの上書き許可
    jCheckOverWrite = new JCheckBox("出力ファイル上書き", true);
    jCheckOverWrite.setFocusPainted(false);
    panel.add(jCheckOverWrite);

    ////////////////////////////////
    //出力先 履歴をpropsから読み込んで設定
    ////////////////////////////////
    dstPathChooser = new DstPathChooserListener(this);

    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setMinimumSize(panelSize);
    panel.setMaximumSize(panelSize);
    panel.setPreferredSize(panelSize);
    panel.setBorder(padding4H2V);
    tabPanel.add(panel);
    //出力先
    label = new JLabel("出力先: ");
    panel.add(label);
    jCheckSamePath = new JCheckBox("入力と同じ", true);
    jCheckSamePath.setToolTipText("入力ファイルと同じ場所に出力します");
    panel.add(jCheckSamePath);
    jCheckSamePath.addChangeListener(e -> {
        jComboDstPath.setEditable(!jCheckSamePath.isSelected());
        jComboDstPath.setForeground(jCheckSamePath.isSelected()?Color.gray:Color.black);
        jComboDstPath.repaint();
    });
    jComboDstPath = new JComboBox<String>();
    jComboDstPath.setToolTipText("出力先を指定します。変換時に履歴に追加されます。フォルダのドロップでも設定できます");
    jComboDstPath.setEditable(false);
    jComboDstPath.setForeground(Color.gray);
    jComboDstPath.setPreferredSize(new Dimension(260, 24));
    //パスを追加
    //vecDstPath.add("[入力ファイルと同じ場所]");
    String propValue = props.getProperty("DstPathList");
    String dstPath = props.getProperty("DstPath");
    if (propValue!=null && !propValue.isEmpty()) {
        for (String listPath : propValue.split(",")) {
            if (!"".equals(listPath)) jComboDstPath.addItem(listPath);
        }
    }
    if (dstPath!=null && !dstPath.isEmpty()) {
        jComboDstPath.setSelectedItem(dstPath);
    }
    panel.add(jComboDstPath);
    new DropTarget(jComboDstPath.getEditor().getEditorComponent(), DnDConstants.ACTION_COPY_OR_MOVE, new DropDstPathListener(), true);
    //選択解除
    if ("".equals(props.getProperty("SamePath"))) jCheckSamePath.setSelected(false);

    jButtonDstPath = new JButton("選択");
    jButtonDstPath.setBorder(padding3);
    jButtonDstPath.setIcon(new ImageIcon(Objects.requireNonNull(AozoraEpub3Applet.class.getResource("images/dst_path.png"))));
    jButtonDstPath.setFocusPainted(false);
    jButtonDstPath.addActionListener(dstPathChooser);
    panel.add(jButtonDstPath);

    ////////////////////////////////
    /*group = new ButtonGroup();
    jRadioRtL = new JRadioButton("右→左");
    jRadioRtL.setFocusPainted(false);
    panel.add(jRadioRtL);
    group.add(jRadioRtL);
    jRadioLtR = new JRadioButton("左→右");
    jRadioLtR.setFocusPainted(false);
    panel.add(jRadioLtR);
    group.add(jRadioLtR);*/

    ////////////////////////////////
    //変換
    ////////////////////////////////
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setMaximumSize(new Dimension(1920, 32));
    panel.setPreferredSize(new Dimension(1920, 32));
    panel.setBorder(padding4H);
    tabPanel.add(panel);
    //左パネル
    JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
    //panel1.setPreferredSize(panelSize);
    panel1.setBorder(padding0);
    //入力文字コード
    label = new JLabel("入力文字コード");
    label.setBorder(padding0);
    panel1.add(label);

    jComboEncType = new JComboBox<String>(new String[]{"AUTO","MS932", "UTF-8"});
    jComboEncType.setToolTipText("入力ファイルのテキストファイルの文字コード。青空文庫の標準はMS932(SJIS)です");
    jComboEncType.setFocusable(false);
    jComboEncType.setPreferredSize(new Dimension(70, 22));
    panel1.add(jComboEncType);

    label = new JLabel("言語");
    label.setBorder(padding0);
    panel1.add(label);
    jComboLangType = new JComboBox<String>(new String[]{"ja", "en"});
    jComboLangType.setToolTipText("出力するEPUBの言語を選択する。");
    jComboLangType.setEditable(true);
    //jComboLangType.setFocusable(false);
    jComboLangType.setPreferredSize(new Dimension(70, 22));
    panel1.add(jComboLangType);
    panel.add(panel1);

    //右パネル
    JPanel panel2 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
    //panel2.setPreferredSize(panelSize);
    panel.setBorder(padding0);
    //縦書き横書き
    buttonGroup = new ButtonGroup();
    jRadioVertical = new JRadioButton();
    jRadioVertical.setSelected(true);
    jRadioVertical.setFocusPainted(false);
    //jRadioVertical.setBorder(BorderFactory.createEmptyBorder(0, 100, 0, 0));
    jRadioVertical.setBorder(padding0);
    jRadioVertical.setIconTextGap(0);
    label = new JLabel("縦書き", new ImageIcon(Objects.requireNonNull(AozoraEpub3Applet.class.getResource("images/page_vertical.png"))), JLabel.LEFT);
    label.setBorder(iconPadding);
    jRadioVertical.add(label);
    panel2.add(jRadioVertical);
    buttonGroup.add(jRadioVertical);
    jRadioHorizontal = new JRadioButton();
    jRadioHorizontal.setFocusPainted(false);
    jRadioHorizontal.setBorder(padding0);
    jRadioHorizontal.setIconTextGap(0);
    label = new JLabel("横書き ", new ImageIcon(Objects.requireNonNull(AozoraEpub3Applet.class.getResource("images/page_horizontal.png"))), JLabel.LEFT);
    label.setBorder(iconPadding);
    jRadioHorizontal.add(label);
    panel2.add(jRadioHorizontal);
    buttonGroup.add(jRadioHorizontal);
    //ファイル選択
    jButtonFile = new JButton("ファイル選択");
    jButtonFile.setToolTipText("ファイル選択後に変換処理を開始します");
    jButtonFile.setBorder(padding5H3V);
    //jButtonFile.setPreferredSize(new Dimension(100, 24));
    jButtonFile.setIcon(new ImageIcon(Objects.requireNonNull(AozoraEpub3Applet.class.getResource("images/convert.png"))));
    jButtonFile.setFocusPainted(false);
    jButtonFile.addActionListener(new FileChooserListener(this));
    panel2.add(jButtonFile);
    panel.add(panel2);

ChatGPT:

このSwingのUIコードをAndroidのPreferenceScreenに書き換えるには、PreferenceFragmentCompatを使用してXMLベースで構成するのが基本的な方法です。以下に、可能な限り近いAndroid PreferenceScreen 表現をXMLで示し、その後、必要に応じて PreferenceFragmentCompat クラスでの処理を記述します。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 出力ファイル設定 -->
    <PreferenceCategory android:title="出力ファイル設定">

        <ListPreference
            android:key="file_extension"
            android:title="拡張子"
            android:summary="出力するファイルの拡張子"
            android:entries=".epub,.kepub.epub,.fxl.kepub.epub,.mobi,.mobi+.epub"
            android:entryValues=".epub,.kepub.epub,.fxl.kepub.epub,.mobi,.mobi+.epub"
            android:defaultValue=".epub" />

        <SwitchPreferenceCompat
            android:key="use_title_for_filename"
            android:title="出力ファイル名に表題利用"
            android:defaultValue="true" />

        <SwitchPreferenceCompat
            android:key="overwrite_output"
            android:title="出力ファイル上書き"
            android:defaultValue="true" />
    </PreferenceCategory>

    <!-- 出力先 -->
    <PreferenceCategory android:title="出力先">

        <SwitchPreferenceCompat
            android:key="same_path"
            android:title="入力と同じ場所に出力"
            android:defaultValue="true" />

        <EditTextPreference
            android:key="output_path"
            android:title="出力先フォルダ"
            android:summary="出力先を指定します"
            android:dialogTitle="フォルダパスを入力"
            android:enabled="false" />
    </PreferenceCategory>

    <!-- 変換 -->
    <PreferenceCategory android:title="変換設定">

        <ListPreference
            android:key="input_encoding"
            android:title="入力文字コード"
            android:entries="AUTO,MS932,UTF-8"
            android:entryValues="AUTO,MS932,UTF-8"
            android:defaultValue="AUTO" />

        <ListPreference
            android:key="language"
            android:title="言語"
            android:entries="日本語, 英語"
            android:entryValues="ja,en"
            android:defaultValue="ja" />

        <ListPreference
            android:key="text_direction"
            android:title="レイアウト方向"
            android:entries="縦書き, 横書き"
            android:entryValues="vertical,horizontal"
            android:defaultValue="vertical" />

        <Preference
            android:key="select_file"
            android:title="ファイル選択"
            android:summary="ファイルを選択して変換を開始"
        />
    </PreferenceCategory>

</PreferenceScreen>
class OutputSettingsFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences_output, rootKey)

        val samePathPref = findPreference<SwitchPreferenceCompat>("same_path")
        val outputPathPref = findPreference<EditTextPreference>("output_path")

        samePathPref?.setOnPreferenceChangeListener { _, newValue ->
            val enabled = !(newValue as Boolean)
            outputPathPref?.isEnabled = enabled
            true
        }

        val fileSelect = findPreference<Preference>("select_file")
        fileSelect?.setOnPreferenceClickListener {
            // ファイル選択ダイアログ処理をここに
            true
        }
    }
}
  • DropTarget のようなドラッグ&ドロップ機能は PreferenceScreen ではサポートされていないため、別途 UI を用意して Activity / Fragment 側で実装します。
  • 「アイコン付きラジオボタン」なども Preference では制限があるため、カスタム UI が必要になることがあります。

DropTarget のようなドラッグ&ドロップ機能は PreferenceScreen ではサポートされていないため、別途 UI を用意して Activity / Fragment 側で実装します。

「アイコン付きラジオボタン」なども Preference では制限があるため、カスタム UI が必要になることがあります。

この形式で問題ないですか? それとも、Preferenceではなく通常のFragmentやActivityでレイアウトを作る方が希望ですか?

あなた:

ドラッグ&ドロップ機能ha

ChatGPT:

了解です、「ドラッグ&ドロップ機能は?」ですね! Androidでファイルやフォルダのドラッグ&ドロップ機能を実装する場合、PreferenceScreenのようなシンプルな設定UIでは基本的に 非対応 です。ただし、通常のFragmentやActivityのカスタムビューを使えば、ドラッグ&ドロップ機能を実現できます。

通常のView(たとえばEditText, TextView, LinearLayoutなど)に以下のようなリスナーを設定して実現します:

val dropTarget = findViewById<EditText>(R.id.editTextPath)
dropTarget.setOnDragListener { v, event ->
    when (event.action) {
        DragEvent.ACTION_DRAG_STARTED -> {
            true
        }
        DragEvent.ACTION_DROP -> {
            val item: ClipData.Item = event.clipData.getItemAt(0)
            val path = item.uri.path  // ここでパス取得
            dropTarget.setText(path)
            true
        }
        else -> false
    }
}

PreferenceScreenではなく、FragmentやActivityの中で以下のようなUIを作って実現します:

<!-- res/layout/fragment_output_settings.xml -->
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/editTextPath"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="ここにフォルダをドロップ"
        android:focusable="false"
        android:background="@drawable/edit_text_border" />

</LinearLayout>

Androidではユーザーがファイルマネージャーなどから直接ドラッグしてくるケースは少ないです。 そのため通常は以下の方法を組み合わせます:

  • フォルダ選択ダイアログ(Storage Access Framework)
  • 「共有」メニューから受け取る
  • 端末内でのドラッグ&ドロップ(同アプリ内のリストビュー間など)

フォルダ選択ダイアログ(Storage Access Framework)

「共有」メニューから受け取る

端末内でのドラッグ&ドロップ(同アプリ内のリストビュー間など)

操作 Androidでの一般的な対応方法
ドラッグしてパスを設定 フォルダ選択ダイアログ or SAFを使う
ドラッグしてファイルを読み込み Intent.ACTION_GET_CONTENTを使う
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
startActivityForResult(intent, REQUEST_CODE_PICK_FOLDER)

その後、選ばれたフォルダのURIを保存・使用できます。

  • PreferenceScreenはドラッグ&ドロップに不向き。
  • 通常のFragment + EditText + setOnDragListenerで実装可能。
  • 外部からのドラッグは限定的なので、代替としてフォルダ選択ダイアログを使うのが一般的。

PreferenceScreenはドラッグ&ドロップに不向き。

通常のFragment + EditText + setOnDragListenerで実装可能。

外部からのドラッグは限定的なので、代替としてフォルダ選択ダイアログを使うのが一般的。

ドラッグ&ドロップ機能を実装したいのは「出力先パス」だけですか? それとも他にもファイル選択や設定項目がありますか?どこまでをドラッグ対応にしたいか教えてもらえたら、よりピッタリなコードにできます!

あなた:

下記のコードをAndroidのpreferenceに書き換えて

    ////////////////////////////////////////////////////////////////
    //Tab 画像配置
    ////////////////////////////////////////////////////////////////
    tabPanel = new JPanel();
    //tabPanel.setLayout(new BoxLayout(tabPanel, BoxLayout.Y_AXIS));
    tabPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 1, 0));
    jTabbedPane.addTab("画像1", imageIcon, tabPanel);

    ////////////////////////////////
    //挿絵なし
    ////////////////////////////////
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("画像注記"));
    tabPanel.add(panel);
    jCheckNoIllust = new JCheckBox("挿絵除外 ");
    jCheckNoIllust.setFocusPainted(false);
    jCheckNoIllust.setToolTipText("テキストの画像注記は表紙と外字画像以外はePubに格納されません");
    jCheckNoIllust.setBorder(padding2);
    panel.add(jCheckNoIllust);

    ////////////////////////////////
    //画面サイズ
    ////////////////////////////////
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("画面・表紙サイズ"));
    tabPanel.add(panel);
    //画面サイズ
    label = new JLabel(" 画面: 横");
    panel.add(label);
    jTextDispW = new JTextField("1600");
    jTextDispW.setHorizontalAlignment(JTextField.RIGHT);
    jTextDispW.setMaximumSize(text4);
    jTextDispW.setPreferredSize(text4);
    jTextDispW.addFocusListener(new TextSelectFocusListener(jTextDispW));
    jTextDispW.setInputVerifier(new IntegerInputVerifier(600, 1, 9999));
    panel.add(jTextDispW);
    label = new JLabel("x");
    label.setBorder(padding2H);
    panel.add(label);
    label = new JLabel("縦");
    panel.add(label);
    jTextDispH = new JTextField("2560");
    jTextDispH.setHorizontalAlignment(JTextField.RIGHT);
    jTextDispH.setMaximumSize(text4);
    jTextDispH.setPreferredSize(text4);
    jTextDispH.addFocusListener(new TextSelectFocusListener(jTextDispH));
    jTextDispH.setInputVerifier(new IntegerInputVerifier(800, 1, 9999));
    panel.add(jTextDispH);
    label = new JLabel("px");
    label.setBorder(padding2H);
    panel.add(label);
    ////////////////////////////////
    //表紙サイズ
    //横x縦
    label = new JLabel("  表紙: 横");
    panel.add(label);
    jTextCoverW = new JTextField("0");
    jTextCoverW.setHorizontalAlignment(JTextField.RIGHT);
    jTextCoverW.setInputVerifier(new IntegerInputVerifier(600, 0, 4096));
    jTextCoverW.setMaximumSize(text4);
    jTextCoverW.setPreferredSize(text4);
    jTextCoverW.addFocusListener(new TextSelectFocusListener(jTextCoverW));
    panel.add(jTextCoverW);
    label = new JLabel("x");
    label.setBorder(padding2H);
    panel.add(label);
    label = new JLabel("縦");
    panel.add(label);
    jTextCoverH = new JTextField("0");
    jTextCoverH.setHorizontalAlignment(JTextField.RIGHT);
    jTextCoverH.setInputVerifier(new IntegerInputVerifier(800, 0, 4096));
    jTextCoverH.setMaximumSize(text4);
    jTextCoverH.setPreferredSize(text4);
    jTextCoverH.addFocusListener(new TextSelectFocusListener(jTextCoverH));
    panel.add(jTextCoverH);
    label = new JLabel("px");
    label.setBorder(padding2H);
    panel.add(label);


    ////////////////////////////////
    //画像倍率
    ////////////////////////////////
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("画像表示倍率"));
    tabPanel.add(panel);
    jCheckImageScale = new JCheckBox("有効 ", true);
    jCheckImageScale.setToolTipText("画面の解像度に合わせて画像の幅を%指定します。画像キャプションがはみ出る場合も指定してください");
    jCheckImageScale.setFocusPainted(false);
    jCheckImageScale.setBorder(padding2);
    jCheckImageScale.addChangeListener(e -> jTextImageScale.setEditable(jCheckImageScale.isSelected()));
    panel.add(jCheckImageScale);
    jTextImageScale = new JTextField("1.0");
    jTextImageScale.setToolTipText("指定倍率で画像を拡大表示します。64px以下の画像は変更されません");
    jTextImageScale.setHorizontalAlignment(JTextField.RIGHT);
    jTextImageScale.setInputVerifier(new FloatInputVerifier(1, 0.01f, 30));
    jTextImageScale.setMaximumSize(text4);
    jTextImageScale.setPreferredSize(text4);
    jTextImageScale.addFocusListener(new TextSelectFocusListener(jTextImageScale));
    panel.add(jTextImageScale);
    label = new JLabel("倍");
    panel.add(label);

ChatGPT:

AndroidのPreferenceScreenにSwingの「画像配置」タブ(挿絵除外、画面サイズ、表紙サイズ、画像表示倍率)を置き換えるには、PreferenceFragmentCompatまたはPreferenceScreen XMLを使って構築するのが一般的です。

以下にそのコードの変換例を紹介します。UIの見た目はSwingと異なりますが、設定値の保存・取得が容易で、ユーザーにとっても馴染みある形式になります。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 挿絵除外 -->
    <CheckBoxPreference
        android:key="exclude_illustrations"
        android:title="挿絵除外"
        android:summary="テキストの画像注記は表紙と外字画像以外はePubに格納されません"
        android:defaultValue="false" />

    <!-- 画面サイズ -->
    <PreferenceCategory android:title="画面・表紙サイズ">

        <EditTextPreference
            android:key="screen_width"
            android:title="画面 横(px)"
            android:inputType="number"
            android:defaultValue="1600" />

        <EditTextPreference
            android:key="screen_height"
            android:title="画面 縦(px)"
            android:inputType="number"
            android:defaultValue="2560" />

        <EditTextPreference
            android:key="cover_width"
            android:title="表紙 横(px)"
            android:inputType="number"
            android:defaultValue="0" />

        <EditTextPreference
            android:key="cover_height"
            android:title="表紙 縦(px)"
            android:inputType="number"
            android:defaultValue="0" />

    </PreferenceCategory>

    <!-- 画像倍率 -->
    <PreferenceCategory android:title="画像表示倍率">

        <CheckBoxPreference
            android:key="image_scale_enabled"
            android:title="有効"
            android:summary="画面の解像度に合わせて画像の幅を%指定します"
            android:defaultValue="true" />

        <EditTextPreference
            android:key="image_scale_factor"
            android:title="画像表示倍率(倍)"
            android:inputType="numberDecimal"
            android:defaultValue="1.0" />
    </PreferenceCategory>

</PreferenceScreen>
class ImageSettingsFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences_image, rootKey)

        val imageScalePref = findPreference<EditTextPreference>("image_scale_factor")
        val scaleEnabled = findPreference<CheckBoxPreference>("image_scale_enabled")

        scaleEnabled?.setOnPreferenceChangeListener { _, newValue ->
            imageScalePref?.isEnabled = newValue as Boolean
            true
        }

        imageScalePref?.isEnabled = scaleEnabled?.isChecked == true
    }
}
  • EditTextPreferenceはバリデーションを手動で入れる必要があります(例えば数値範囲チェック)。
  • CheckBoxPreferenceで連動制御(有効/無効)したい場合はKotlinやJavaで設定する必要があります。
  • 表示倍率やサイズの制限(最大値・最小値など)を厳密に扱うなら、DialogPreferenceをカスタム実装する方法もあります。

EditTextPreferenceはバリデーションを手動で入れる必要があります(例えば数値範囲チェック)。

CheckBoxPreferenceで連動制御(有効/無効)したい場合はKotlinやJavaで設定する必要があります。

表示倍率やサイズの制限(最大値・最小値など)を厳密に扱うなら、DialogPreferenceをカスタム実装する方法もあります。

必要であれば、この設定に対応する SharedPreferences の読み書きコードや、バリデーション付きのカスタム DialogPreference の実装も用意できます。やってみますか?

あなた:

下記のコードをAndroidのpreferenceに書き換えて

    ////////////////////////////////
    //画像回り込み
    ////////////////////////////////
    //画像回り込み
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("画像回り込み (※単ページ化より優先)"));
    tabPanel.add(panel);

    jCheckImageFloat = new JCheckBox("回り込み有効 ");
    jCheckImageFloat.setToolTipText("画像の実サイズが指定サイズ以下の画像を回り込み設定します");
    jCheckImageFloat.setFocusPainted(false);
    jCheckImageFloat.setBorder(padding2);
    jCheckImageFloat.addChangeListener(e -> { jTextImageFloatW.setEditable(jCheckImageFloat.isSelected()); jTextImageFloatH.setEditable(jCheckImageFloat.isSelected());});
    panel.add(jCheckImageFloat);
    label = new JLabel("横");
    panel.add(label);
    jTextImageFloatW = new JTextField("600");
    jTextImageFloatW.setHorizontalAlignment(JTextField.RIGHT);
    jTextImageFloatW.setInputVerifier(new IntegerInputVerifier(600, 1, 9999));
    jTextImageFloatW.setMaximumSize(text4);
    jTextImageFloatW.setPreferredSize(text4);
    jTextImageFloatW.addFocusListener(new TextSelectFocusListener(jTextImageFloatW));
    jTextImageFloatW.setEditable(jCheckImageFloat.isSelected());
    panel.add(jTextImageFloatW);
    label = new JLabel("x");
    label.setBorder(padding2H);
    panel.add(label);
    label = new JLabel("縦");
    panel.add(label);
    jTextImageFloatH = new JTextField("400");
    jTextImageFloatH.setHorizontalAlignment(JTextField.RIGHT);
    jTextImageFloatH.setInputVerifier(new IntegerInputVerifier(400, 1, 9999));
    jTextImageFloatH.setMaximumSize(text4);
    jTextImageFloatH.setPreferredSize(text4);
    jTextImageFloatH.addFocusListener(new TextSelectFocusListener(jTextImageFloatH));
    jTextImageFloatH.setEditable(jCheckImageFloat.isSelected());
    panel.add(jTextImageFloatH);
    label = new JLabel("px以下");
    label.setBorder(padding2H);
    panel.add(label);

    label = new JLabel(" 配置");
    panel.add(label);
    jComboImageFloatType = new JComboBox<String>(new String[]{"上/左","下/右"});
    jComboImageFloatType.setFocusable(false);
    jComboImageFloatType.setBorder(padding0);
    jComboImageFloatType.setPreferredSize(new Dimension(text4.width+24, 20));
    panel.add(jComboImageFloatType);

    ////////////////////////////////
    //画像単ページ化
    ////////////////////////////////
    panelV = new JPanel();
    panelV.setLayout(new BoxLayout(panelV, BoxLayout.Y_AXIS));
    panelV.setBorder(new NarrowTitledBorder("画像単ページ化"));
    tabPanel.add(panelV);
    //上段
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setMaximumSize(panelVMaxSize);
    panel.setBorder(padding4B);
    panelV.add(panel);

    //横x縦
    label = new JLabel("横");
    panel.add(label);
    jTextSinglePageSizeW = new JTextField("200");
    jTextSinglePageSizeW.setHorizontalAlignment(JTextField.RIGHT);
    jTextSinglePageSizeW.setInputVerifier(new IntegerInputVerifier(400, 1, 9999));
    jTextSinglePageSizeW.setMaximumSize(text4);
    jTextSinglePageSizeW.setPreferredSize(text4);
    jTextSinglePageSizeW.addFocusListener(new TextSelectFocusListener(jTextSinglePageSizeW));
    panel.add(jTextSinglePageSizeW);
    label = new JLabel("x");
    label.setBorder(padding2H);
    panel.add(label);
    label = new JLabel("縦");
    panel.add(label);
    jTextSinglePageSizeH = new JTextField("300");
    jTextSinglePageSizeH.setHorizontalAlignment(JTextField.RIGHT);
    jTextSinglePageSizeH.setInputVerifier(new IntegerInputVerifier(600, 1, 9999));
    jTextSinglePageSizeH.setMaximumSize(text4);
    jTextSinglePageSizeH.setPreferredSize(text4);
    jTextSinglePageSizeH.addFocusListener(new TextSelectFocusListener(jTextSinglePageSizeH));
    panel.add(jTextSinglePageSizeH);
    label = new JLabel("px以上 ");
    label.setBorder(padding2H);
    panel.add(label);
    //横のみ
    label = new JLabel("横のみ");
    label.setBorder(padding2H);
    panel.add(label);
    jTextSinglePageWidth = new JTextField("300");
    jTextSinglePageWidth.setHorizontalAlignment(JTextField.RIGHT);
    jTextSinglePageWidth.setInputVerifier(new IntegerInputVerifier(600, 1, 9999));
    jTextSinglePageWidth.setMaximumSize(text4);
    jTextSinglePageWidth.setPreferredSize(text4);
    jTextSinglePageWidth.addFocusListener(new TextSelectFocusListener(jTextSinglePageWidth));
    panel.add(jTextSinglePageWidth);
    label = new JLabel("px以上");
    label.setBorder(padding2H);
    panel.add(label);

    //下段
    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
    panelV.add(panel);

    label = new JLabel("縮小表示 (");
    label.setBorder(padding2H);
    panel.add(label);

    buttonGroup = new ButtonGroup();
    jRadioImageSizeType1 = new JRadioButton("指定無し");
    jRadioImageSizeType1.setToolTipText("画像のサイズを指定しません。 端末が自動で縮小します(Kindle, Kobo)");
    jRadioImageSizeType1.setFocusPainted(false);
    jRadioImageSizeType1.setBorder(padding2);
    jRadioImageSizeType1.setIconTextGap(1);
    panel.add(jRadioImageSizeType1);
    buttonGroup.add(jRadioImageSizeType1);
    /*jRadioImageSizeType2 = new JRadioButton("高さ%", true);
    jRadioImageSizeType2.setToolTipText("画面の縦横比に合せて画像の高さのみ%指定します。画面設定より縦長の端末でははみ出すか縦長に表示されます");
    jRadioImageSizeType2.setFocusPainted(false);
    jRadioImageSizeType2.setBorder(padding2);
    jRadioImageSizeType2.setIconTextGap(1);
    panel.add(jRadioImageSizeType2);
    buttonGroup.add(jRadioImageSizeType2);*/
    jRadioImageSizeType3 = new JRadioButton("縦横比");
    jRadioImageSizeType3.setToolTipText("画面の縦横比に合せて幅または高さを100%指定します。画面回転で画像がはみ出す場合があります");
    jRadioImageSizeType3.setFocusPainted(false);
    jRadioImageSizeType3.setBorder(padding2);
    jRadioImageSizeType3.setIconTextGap(1);
    panel.add(jRadioImageSizeType3);
    buttonGroup.add(jRadioImageSizeType3);

    label = new JLabel(")  ");
    label.setBorder(padding2H);
    panel.add(label);

    jCheckFitImage = new JCheckBox("拡大表示", true);
    jCheckFitImage.setToolTipText("画面サイズより小さい画像を幅高さに合わせて拡大表示します。画面回転で画像がはみ出す場合があります");
    jCheckFitImage.setFocusPainted(false);
    jCheckFitImage.setBorder(padding2);
    panel.add(jCheckFitImage);
    buttonGroup = new ButtonGroup();

ChatGPT:

以下は、指定されたSwing UIの「画像回り込み」と「画像単ページ化」に関する設定を、AndroidのPreferenceScreen形式に書き換えた例です。PreferenceFragmentCompatで実装することを想定しています。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- 画像回り込み -->
    <PreferenceCategory android:title="画像回り込み (※単ページ化より優先)">
        <SwitchPreferenceCompat
            android:key="image_float_enabled"
            android:title="回り込み有効"
            android:summary="画像の実サイズが指定サイズ以下の画像を回り込み設定します"
            android:defaultValue="false" />

        <EditTextPreference
            android:key="image_float_width"
            android:title="横 (px)"
            android:dialogTitle="画像回り込み 横サイズ"
            android:inputType="number"
            android:defaultValue="600" />

        <EditTextPreference
            android:key="image_float_height"
            android:title="縦 (px)"
            android:dialogTitle="画像回り込み 縦サイズ"
            android:inputType="number"
            android:defaultValue="400" />

        <ListPreference
            android:key="image_float_position"
            android:title="配置"
            android:defaultValue="上/左"
            android:entries="@array/image_float_position_entries"
            android:entryValues="@array/image_float_position_values" />
    </PreferenceCategory>

    <!-- 画像単ページ化 -->
    <PreferenceCategory android:title="画像単ページ化">
        <EditTextPreference
            android:key="single_page_width"
            android:title="単ページ 横 (px)"
            android:inputType="number"
            android:defaultValue="200" />

        <EditTextPreference
            android:key="single_page_height"
            android:title="単ページ 縦 (px)"
            android:inputType="number"
            android:defaultValue="300" />

        <EditTextPreference
            android:key="single_page_width_only"
            android:title="横のみ (px)"
            android:inputType="number"
            android:defaultValue="300" />

        <ListPreference
            android:key="image_size_mode"
            android:title="縮小表示モード"
            android:defaultValue="none"
            android:entries="@array/image_size_mode_entries"
            android:entryValues="@array/image_size_mode_values" />

        <SwitchPreferenceCompat
            android:key="fit_image"
            android:title="拡大表示"
            android:summary="画面サイズより小さい画像を幅高さに合わせて拡大表示します"
            android:defaultValue="true" />
    </PreferenceCategory>

</PreferenceScreen>
<resources>
    <string-array name="image_float_position_entries">
        <item>上/左</item>
        <item>下/右</item>
    </string-array>
    <string-array name="image_float_position_values">
        <item>top_left</item>
        <item>bottom_right</item>
    </string-array>

    <string-array name="image_size_mode_entries">
        <item>指定無し</item>
        <item>縦横比</item>
    </string-array>
    <string-array name="image_size_mode_values">
        <item>none</item>
        <item>aspect_ratio</item>
    </string-array>
</resources>
class ImagePreferenceFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.image_preferences, rootKey)
    }
}

必要であれば、数値範囲(例: 1〜9999)や動的なEditable制御(SwitchとEditTextの連動)もPreference.OnPreferenceChangeListenerを使って対応可能です。実装例が必要であれば追加します!

どうします?次はその辺のロジックも書きますか?

あなた:

下記のコードをAndroidのpreferenceに書き換えて

    //Float表示
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("Float指定 (Readerのみ)"));
    tabPanel.add(panel);
    jCheckImageFloatPage = new JCheckBox("単ページ画像");
    jCheckImageFloatPage.setToolTipText("単ページ対象の画像をfloat表示します。 xhtmlは分割されません");
    jCheckImageFloatPage.setFocusPainted(false);
    jCheckImageFloatPage.setBorder(padding2);
    panel.add(jCheckImageFloatPage);

    jCheckImageFloatBlock = new JCheckBox("通常画像");
    jCheckImageFloatBlock.setToolTipText("回り込み、単ページ以外の画像をfloat表示します。 64px以上の画像のみ");
    jCheckImageFloatBlock.setFocusPainted(false);
    jCheckImageFloatBlock.setBorder(padding2);
    panel.add(jCheckImageFloatBlock);

    ////////////////////////////////////////////////////////////////
    //Tab 画像2
    ////////////////////////////////////////////////////////////////
    tabPanel = new JPanel();
    //tabPanel.setLayout(new BoxLayout(tabPanel, BoxLayout.Y_AXIS));
    tabPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 1, 0));
    jTabbedPane.addTab("画像2", imageIcon, tabPanel);

    ////////////////////////////////
    //全画面+SVG
    ////////////////////////////////
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("全画面表示"));
    tabPanel.add(panel);
    jCheckSvgImage = new JCheckBox("SVGタグ出力(画像zipのみ) ");
    jCheckSvgImage.setFocusPainted(false);
    jCheckSvgImage.setToolTipText("画像のみのzipの場合、固定レイアウト+SVGタグで出力します");
    jCheckSvgImage.setBorder(padding2);
    panel.add(jCheckSvgImage);

    ////////////////////////////////
    //画像調整
    ////////////////////////////////
    //Jpeg圧縮率
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("Jpeg圧縮率"));
    tabPanel.add(panel);
    jTextJpegQuality = new JTextField("85");
    jTextJpegQuality.setToolTipText("表紙編集、縮小、回転、余白除去時のJpeg保存時の画質(100が最高画質)");
    jTextJpegQuality.setHorizontalAlignment(JTextField.RIGHT);
    jTextJpegQuality.setInputVerifier(new IntegerInputVerifier(85, 30, 100));
    jTextJpegQuality.setMaximumSize(text3);
    jTextJpegQuality.setPreferredSize(text3);
    jTextJpegQuality.addFocusListener(new TextSelectFocusListener(jTextJpegQuality));
    panel.add(jTextJpegQuality);
    panel.add(new JLabel(" (30~100)"));

    ////////////////////////////////
    //ガンマ補正
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("色調整"));
    tabPanel.add(panel);
    jCheckGamma = new JCheckBox("ガンマ補正");
    jCheckGamma.setToolTipText("画像の濃さを変更します (濃:0.2~1.8:淡)");
    jCheckGamma.setFocusPainted(false);
    jCheckGamma.setBorder(padding2);
    jCheckGamma.setIconTextGap(2);
    jCheckGamma.addChangeListener(e -> jTextGammaValue.setEditable(jCheckGamma.isSelected()));
    panel.add(jCheckGamma);
    jTextGammaValue = new JTextField("1.0");
    jTextGammaValue.setToolTipText(jCheckGamma.getToolTipText());
    jTextGammaValue.setHorizontalAlignment(JTextField.RIGHT);
    jTextGammaValue.setInputVerifier(new FloatInputVerifier(1.0f, 0.2f, 1.8f));
    jTextGammaValue.setMaximumSize(text3);
    jTextGammaValue.setPreferredSize(text3);
    jTextGammaValue.setEditable(jCheckGamma.isSelected());
    jTextGammaValue.addFocusListener(new TextSelectFocusListener(jTextGammaValue));
    panel.add(jTextGammaValue);

    ////////////////////////////////
    //画像縮小
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(new NarrowTitledBorder("画像縮小回転"));
    tabPanel.add(panel);
    ChangeListener resizeChangeLister = e -> setResizeTextEditable(true);
    //横
    jCheckResizeW = new JCheckBox("横");
    jCheckResizeW.setFocusPainted(false);
    jCheckResizeW.setBorder(padding2);
    jCheckResizeW.setIconTextGap(2);
    jCheckResizeW.addChangeListener(resizeChangeLister);
    panel.add(jCheckResizeW);
    jTextResizeNumW = new JTextField("2048");
    jTextResizeNumW.setHorizontalAlignment(JTextField.RIGHT);
    jTextResizeNumW.setInputVerifier(new IntegerInputVerifier(2048, 100, 9999));
    jTextResizeNumW.setMaximumSize(text4);
    jTextResizeNumW.setPreferredSize(text4);
    jTextResizeNumW.addFocusListener(new TextSelectFocusListener(jTextResizeNumW));
    jTextResizeNumW.setEditable(jCheckResizeW.isSelected());
    panel.add(jTextResizeNumW);
    label = new JLabel("px以下 ");
    label.setBorder(padding2H);
    panel.add(label);
    //縦
    jCheckResizeH = new JCheckBox("縦");
    jCheckResizeH.setFocusPainted(false);
    jCheckResizeH.setBorder(padding2);
    jCheckResizeH.setIconTextGap(2);
    jCheckResizeH.addChangeListener(resizeChangeLister);
    panel.add(jCheckResizeH);
    jTextResizeNumH = new JTextField("2048");
    jTextResizeNumH.setHorizontalAlignment(JTextField.RIGHT);
    jTextResizeNumH.setInputVerifier(new IntegerInputVerifier(2048, 100, 9999));
    jTextResizeNumH.setMaximumSize(text4);
    jTextResizeNumH.setPreferredSize(text4);
    jTextResizeNumH.addFocusListener(new TextSelectFocusListener(jTextResizeNumH));
    panel.add(jTextResizeNumH);
    label = new JLabel("px以下");
    label.setBorder(padding2H);
    panel.add(label);
    this.setResizeTextEditable(true);

    //自動画像回転
    label = new JLabel(" 自動回転");
    label.setBorder(padding2H);
    panel.add(label);
    jComboRotateImage = new JComboBox<String>(new String[]{"なし","右","左"});
    jComboRotateImage.setToolTipText("単ページ時画面の縦横比に合わせて画像を回転します");
    jComboRotateImage.setFocusable(false);
    jComboRotateImage.setBorder(padding0);
    jComboRotateImage.setPreferredSize(new Dimension(text4.width+24, 20));
    panel.add(jComboRotateImage);

ChatGPT:

以下に、提示されたSwingコードをAndroidのPreferenceScreen形式に変換したサンプルを記載します。これはres/xml/preferences.xmlで定義し、PreferenceFragmentCompatから読み込む形を想定しています。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <!-- Float指定 -->
    <PreferenceCategory android:title="Float指定 (Readerのみ)">
        <CheckBoxPreference
            android:key="float_image_single_page"
            android:title="単ページ画像"
            android:summary="単ページ対象の画像をfloat表示します。xhtmlは分割されません" />
        <CheckBoxPreference
            android:key="float_image_block"
            android:title="通常画像"
            android:summary="回り込み、単ページ以外の画像をfloat表示します。64px以上の画像のみ" />
    </PreferenceCategory>

    <!-- 全画面表示 -->
    <PreferenceCategory android:title="全画面表示">
        <CheckBoxPreference
            android:key="output_svg"
            android:title="SVGタグ出力(画像zipのみ)"
            android:summary="画像のみのzipの場合、固定レイアウト+SVGタグで出力します" />
    </PreferenceCategory>

    <!-- Jpeg圧縮率 -->
    <PreferenceCategory android:title="Jpeg圧縮率">
        <EditTextPreference
            android:key="jpeg_quality"
            android:title="圧縮率 (30~100)"
            android:summary="表紙編集、縮小、回転、余白除去時のJpeg保存時の画質(100が最高画質)"
            android:inputType="number" />
    </PreferenceCategory>

    <!-- 色調整 -->
    <PreferenceCategory android:title="色調整">
        <CheckBoxPreference
            android:key="gamma_correction"
            android:title="ガンマ補正"
            android:summary="画像の濃さを変更します (濃:0.2~1.8:淡)" />
        <EditTextPreference
            android:key="gamma_value"
            android:title="ガンマ値"
            android:summary="例: 1.0"
            android:inputType="numberDecimal" />
    </PreferenceCategory>

    <!-- 画像縮小回転 -->
    <PreferenceCategory android:title="画像縮小回転">

        <!-- 横縮小 -->
        <CheckBoxPreference
            android:key="resize_width_enabled"
            android:title="横: 有効化" />
        <EditTextPreference
            android:key="resize_width"
            android:title="横(px以下)"
            android:inputType="number" />

        <!-- 縦縮小 -->
        <CheckBoxPreference
            android:key="resize_height_enabled"
            android:title="縦: 有効化" />
        <EditTextPreference
            android:key="resize_height"
            android:title="縦(px以下)"
            android:inputType="number" />

        <!-- 自動回転 -->
        <ListPreference
            android:key="auto_rotate_image"
            android:title="自動回転"
            android:summary="単ページ時画面の縦横比に合わせて画像を回転します"
            android:entries="@array/rotate_options"
            android:entryValues="@array/rotate_values"
            android:defaultValue="none" />
    </PreferenceCategory>

</PreferenceScreen>
<resources>
    <string-array name="rotate_options">
        <item>なし</item>
        <item>右</item>
        <item>左</item>
    </string-array>
    <string-array name="rotate_values">
        <item>none</item>
        <item>right</item>
        <item>left</item>
    </string-array>
</resources>
public class SettingsFragment extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.preferences, rootKey);

        // 例: gamma_correction によって gamma_value を有効/無効化
        CheckBoxPreference gammaCheck = findPreference("gamma_correction");
        EditTextPreference gammaValue = findPreference("gamma_value");

        if (gammaCheck != null && gammaValue != null) {
            gammaValue.setEnabled(gammaCheck.isChecked());
            gammaCheck.setOnPreferenceChangeListener((preference, newValue) -> {
                gammaValue.setEnabled((Boolean) newValue);
                return true;
            });
        }
    }
}

必要であれば、設定画面のレイアウトカスタム(カテゴリのアイコン表示や分割表示など)もできます。

次に他のパート(画像回り込みや単ページ化)も続けて変換していきますか?

あなた:

下記のコードをAndroidのpreferenceに書き換えて

    ////////////////////////////////
    //余白除去
    ////////////////////////////////
    panelV = new JPanel();
    panelV.setLayout(new BoxLayout(panelV, BoxLayout.Y_AXIS));
    panelV.setBorder(new NarrowTitledBorder("余白除去"));
    tabPanel.add(panelV);
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(padding4B);
    panelV.add(panel);
    jCheckAutoMargin = new JCheckBox("有効 ");
    jCheckAutoMargin.setFocusPainted(false);
    jCheckAutoMargin.setBorder(padding2);
    jCheckAutoMargin.setIconTextGap(2);
    jCheckAutoMargin.addChangeListener(e -> {
        boolean selected = jCheckAutoMargin.isSelected();
        jTextAutoMarginLimitH.setEditable(selected);
        jTextAutoMarginLimitV.setEditable(selected);
        jTextAutoMarginWhiteLevel.setEditable(selected);
        jTextAutoMarginPadding.setEditable(selected);
        jTextAutoMarginNombreSize.setEditable(selected);
    });
    panel.add(jCheckAutoMargin);
    label = new JLabel(" 横");
    label.setToolTipText("横方向の余白除去量の制限 左右の余白の合計");
    panel.add(label);
    jTextAutoMarginLimitH = new JTextField("15");
    jTextAutoMarginLimitH.setToolTipText(label.getToolTipText());
    jTextAutoMarginLimitH.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginLimitH.setInputVerifier(new IntegerInputVerifier(15, 0, 50));
    jTextAutoMarginLimitH.setMaximumSize(text3);
    jTextAutoMarginLimitH.setPreferredSize(text3);
    jTextAutoMarginLimitH.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginLimitH.addFocusListener(new TextSelectFocusListener(jTextAutoMarginLimitH));
    panel.add(jTextAutoMarginLimitH);
    label = new JLabel("%");
    label.setBorder(padding2H);
    panel.add(label);
    label = new JLabel(" 縦");
    label.setToolTipText("縦方向の余白除去量の制限 上下の余白の合計");
    panel.add(label);
    jTextAutoMarginLimitV = new JTextField("15");
    jTextAutoMarginLimitV.setToolTipText(label.getToolTipText());
    jTextAutoMarginLimitV.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginLimitV.setInputVerifier(new IntegerInputVerifier(15, 0, 50));
    jTextAutoMarginLimitV.setMaximumSize(text3);
    jTextAutoMarginLimitV.setPreferredSize(text3);
    jTextAutoMarginLimitV.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginLimitV.addFocusListener(new TextSelectFocusListener(jTextAutoMarginLimitV));
    panel.add(jTextAutoMarginLimitV);
    label = new JLabel("%");
    label.setBorder(padding2H);
    panel.add(label);
    panel.add(label);
    label = new JLabel("  余白追加");
    label.setToolTipText("余白除去後に追加する余白の量(追加部分の画像はそのまま)");
    panel.add(label);
    jTextAutoMarginPadding = new JTextField("1.0");
    jTextAutoMarginPadding.setToolTipText(label.getToolTipText());
    jTextAutoMarginPadding.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginPadding.setInputVerifier(new FloatInputVerifier(1.0f, 0, 50));
    jTextAutoMarginPadding.setMaximumSize(text3);
    jTextAutoMarginPadding.setPreferredSize(text3);
    jTextAutoMarginPadding.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginPadding.addFocusListener(new TextSelectFocusListener(jTextAutoMarginPadding));
    panel.add(jTextAutoMarginPadding);
    label = new JLabel("%");
    label.setBorder(padding2H);
    panel.add(label);

    label = new JLabel("  白レベル");
    label.setToolTipText("余白部分の白い画素と判別するレベルを指定します (黒:0~白:100)");
    panel.add(label);
    jTextAutoMarginWhiteLevel = new JTextField("80");
    jTextAutoMarginWhiteLevel.setToolTipText(label.getToolTipText());
    jTextAutoMarginWhiteLevel.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginWhiteLevel.setInputVerifier(new IntegerInputVerifier(80, 0, 100));
    jTextAutoMarginWhiteLevel.setMaximumSize(text3);
    jTextAutoMarginWhiteLevel.setPreferredSize(text3);
    jTextAutoMarginWhiteLevel.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginWhiteLevel.addFocusListener(new TextSelectFocusListener(jTextAutoMarginWhiteLevel));
    panel.add(jTextAutoMarginWhiteLevel);
    label = new JLabel("%");
    label.setBorder(padding2H);

    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
    panelV.add(panel);
    label = new JLabel("ノンブル除去 (位置");
    label.setBorder(padding2H);
    panel.add(label);
    jComboAutoMarginNombre = new JComboBox<String>(new String[]{"なし","上","下","上下"});
    jComboAutoMarginNombre.setToolTipText("ノンブルを除去します。除去した場合は除去制限が5%追加されます");
    jComboAutoMarginNombre.setFocusable(false);
    jComboAutoMarginNombre.setMaximumSize(new Dimension(text3.width+24, 20));
    jComboAutoMarginNombre.setPreferredSize(new Dimension(text3.width+24, 20));
    panel.add(jComboAutoMarginNombre);
    label = new JLabel(" 高さ");
    label.setBorder(padding2H);
    panel.add(label);
    jTextAutoMarginNombreSize = new JTextField("3.0");
    jTextAutoMarginNombreSize.setToolTipText("ノンブルの文字部分の高さを指定します。これより大きい場合はノンブル除去されません");
    jTextAutoMarginNombreSize.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginNombreSize.setInputVerifier(new FloatInputVerifier(3.0f, 0.5f, 10));
    jTextAutoMarginNombreSize.setMaximumSize(text3);
    jTextAutoMarginNombreSize.setPreferredSize(text3);
    jTextAutoMarginNombreSize.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginNombreSize.addFocusListener(new TextSelectFocusListener(jTextAutoMarginPadding));
    panel.add(jTextAutoMarginNombreSize);
    label = new JLabel("% )");
    label.setBorder(padding2H);
    panel.add(label);

ChatGPT:

以下は、提示されたSwingの余白除去設定UIをAndroidのPreferenceScreenに変換したXML例です。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory android:title="余白除去">

        <!-- 有効 -->
        <CheckBoxPreference
            android:key="trim_enabled"
            android:title="余白除去を有効にする" />

        <!-- 横方向の制限 -->
        <EditTextPreference
            android:key="trim_limit_horizontal"
            android:title="横方向の制限 (%)"
            android:summary="横方向の余白除去量の制限 (左右の余白の合計)"
            android:defaultValue="15"
            android:inputType="number" />

        <!-- 縦方向の制限 -->
        <EditTextPreference
            android:key="trim_limit_vertical"
            android:title="縦方向の制限 (%)"
            android:summary="縦方向の余白除去量の制限 (上下の余白の合計)"
            android:defaultValue="15"
            android:inputType="number" />

        <!-- 余白追加 -->
        <EditTextPreference
            android:key="trim_padding"
            android:title="余白追加 (%)"
            android:summary="余白除去後に追加する余白の量(追加部分の画像はそのまま)"
            android:defaultValue="1.0"
            android:inputType="numberDecimal" />

        <!-- 白レベル -->
        <EditTextPreference
            android:key="trim_white_level"
            android:title="白レベル (%)"
            android:summary="余白部分の白い画素と判別するレベル (黒:0~白:100)"
            android:defaultValue="80"
            android:inputType="number" />

        <!-- ノンブル除去 -->
        <ListPreference
            android:key="trim_nombre_position"
            android:title="ノンブル除去 (位置)"
            android:summary="ノンブルを除去します。除去した場合は除去制限が5%追加されます"
            android:entries="@array/nombre_positions"
            android:entryValues="@array/nombre_values"
            android:defaultValue="none" />

        <!-- ノンブルの高さ -->
        <EditTextPreference
            android:key="trim_nombre_height"
            android:title="ノンブル高さ (%)"
            android:summary="ノンブル文字部分の高さ。これより大きい場合は除去されません"
            android:defaultValue="3.0"
            android:inputType="numberDecimal" />

    </PreferenceCategory>

</PreferenceScreen>
<resources>
    <string-array name="nombre_positions">
        <item>なし</item>
        <item>上</item>
        <item>下</item>
        <item>上下</item>
    </string-array>
    <string-array name="nombre_values">
        <item>none</item>
        <item>top</item>
        <item>bottom</item>
        <item>both</item>
    </string-array>
</resources>

Swing版では jCheckAutoMargin の状態に応じて他の項目が有効/無効化されていました。Androidでも以下のように制御できます:

public class SettingsFragment extends PreferenceFragmentCompat {
    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.preferences_trim, rootKey);

        CheckBoxPreference enabledPref = findPreference("trim_enabled");
        EditTextPreference hLimitPref = findPreference("trim_limit_horizontal");
        EditTextPreference vLimitPref = findPreference("trim_limit_vertical");
        EditTextPreference paddingPref = findPreference("trim_padding");
        EditTextPreference whiteLevelPref = findPreference("trim_white_level");
        EditTextPreference nombreHeightPref = findPreference("trim_nombre_height");
        ListPreference nombrePosPref = findPreference("trim_nombre_position");

        Preference.OnPreferenceChangeListener toggle = (pref, value) -> {
            boolean enabled = (Boolean) value;
            hLimitPref.setEnabled(enabled);
            vLimitPref.setEnabled(enabled);
            paddingPref.setEnabled(enabled);
            whiteLevelPref.setEnabled(enabled);
            nombreHeightPref.setEnabled(enabled);
            nombrePosPref.setEnabled(enabled);
            return true;
        };

        if (enabledPref != null) {
            boolean init = enabledPref.isChecked();
            toggle.onPreferenceChange(null, init);
            enabledPref.setOnPreferenceChangeListener(toggle);
        }
    }
}

SwingのUIの構成がかなり詳細だったため、Android版でもできるだけツールチップや制限に相当する部分を反映させました。

次に別のセクション(たとえばページ回転やトリミング)も変換しますか?

あなた:

下記のコードをAndroidのpreferenceに書き換えて

    ////////////////////////////////
    //余白除去
    ////////////////////////////////
    panelV = new JPanel();
    panelV.setLayout(new BoxLayout(panelV, BoxLayout.Y_AXIS));
    panelV.setBorder(new NarrowTitledBorder("余白除去"));
    tabPanel.add(panelV);
    panel = new JPanel();
    panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
    panel.setBorder(padding4B);
    panelV.add(panel);
    jCheckAutoMargin = new JCheckBox("有効 ");
    jCheckAutoMargin.setFocusPainted(false);
    jCheckAutoMargin.setBorder(padding2);
    jCheckAutoMargin.setIconTextGap(2);
    jCheckAutoMargin.addChangeListener(e -> {
        boolean selected = jCheckAutoMargin.isSelected();
        jTextAutoMarginLimitH.setEditable(selected);
        jTextAutoMarginLimitV.setEditable(selected);
        jTextAutoMarginWhiteLevel.setEditable(selected);
        jTextAutoMarginPadding.setEditable(selected);
        jTextAutoMarginNombreSize.setEditable(selected);
    });
    panel.add(jCheckAutoMargin);
    label = new JLabel(" 横");
    label.setToolTipText("横方向の余白除去量の制限 左右の余白の合計");
    panel.add(label);
    jTextAutoMarginLimitH = new JTextField("15");
    jTextAutoMarginLimitH.setToolTipText(label.getToolTipText());
    jTextAutoMarginLimitH.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginLimitH.setInputVerifier(new IntegerInputVerifier(15, 0, 50));
    jTextAutoMarginLimitH.setMaximumSize(text3);
    jTextAutoMarginLimitH.setPreferredSize(text3);
    jTextAutoMarginLimitH.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginLimitH.addFocusListener(new TextSelectFocusListener(jTextAutoMarginLimitH));
    panel.add(jTextAutoMarginLimitH);
    label = new JLabel("%");
    label.setBorder(padding2H);
    panel.add(label);
    label = new JLabel(" 縦");
    label.setToolTipText("縦方向の余白除去量の制限 上下の余白の合計");
    panel.add(label);
    jTextAutoMarginLimitV = new JTextField("15");
    jTextAutoMarginLimitV.setToolTipText(label.getToolTipText());
    jTextAutoMarginLimitV.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginLimitV.setInputVerifier(new IntegerInputVerifier(15, 0, 50));
    jTextAutoMarginLimitV.setMaximumSize(text3);
    jTextAutoMarginLimitV.setPreferredSize(text3);
    jTextAutoMarginLimitV.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginLimitV.addFocusListener(new TextSelectFocusListener(jTextAutoMarginLimitV));
    panel.add(jTextAutoMarginLimitV);
    label = new JLabel("%");
    label.setBorder(padding2H);
    panel.add(label);
    panel.add(label);
    label = new JLabel("  余白追加");
    label.setToolTipText("余白除去後に追加する余白の量(追加部分の画像はそのまま)");
    panel.add(label);
    jTextAutoMarginPadding = new JTextField("1.0");
    jTextAutoMarginPadding.setToolTipText(label.getToolTipText());
    jTextAutoMarginPadding.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginPadding.setInputVerifier(new FloatInputVerifier(1.0f, 0, 50));
    jTextAutoMarginPadding.setMaximumSize(text3);
    jTextAutoMarginPadding.setPreferredSize(text3);
    jTextAutoMarginPadding.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginPadding.addFocusListener(new TextSelectFocusListener(jTextAutoMarginPadding));
    panel.add(jTextAutoMarginPadding);
    label = new JLabel("%");
    label.setBorder(padding2H);
    panel.add(label);

    label = new JLabel("  白レベル");
    label.setToolTipText("余白部分の白い画素と判別するレベルを指定します (黒:0~白:100)");
    panel.add(label);
    jTextAutoMarginWhiteLevel = new JTextField("80");
    jTextAutoMarginWhiteLevel.setToolTipText(label.getToolTipText());
    jTextAutoMarginWhiteLevel.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginWhiteLevel.setInputVerifier(new IntegerInputVerifier(80, 0, 100));
    jTextAutoMarginWhiteLevel.setMaximumSize(text3);
    jTextAutoMarginWhiteLevel.setPreferredSize(text3);
    jTextAutoMarginWhiteLevel.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginWhiteLevel.addFocusListener(new TextSelectFocusListener(jTextAutoMarginWhiteLevel));
    panel.add(jTextAutoMarginWhiteLevel);
    label = new JLabel("%");
    label.setBorder(padding2H);

    panel = new JPanel();
    panel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
    panelV.add(panel);
    label = new JLabel("ノンブル除去 (位置");
    label.setBorder(padding2H);
    panel.add(label);
    jComboAutoMarginNombre = new JComboBox<String>(new String[]{"なし","上","下","上下"});
    jComboAutoMarginNombre.setToolTipText("ノンブルを除去します。除去した場合は除去制限が5%追加されます");
    jComboAutoMarginNombre.setFocusable(false);
    jComboAutoMarginNombre.setMaximumSize(new Dimension(text3.width+24, 20));
    jComboAutoMarginNombre.setPreferredSize(new Dimension(text3.width+24, 20));
    panel.add(jComboAutoMarginNombre);
    label = new JLabel(" 高さ");
    label.setBorder(padding2H);
    panel.add(label);
    jTextAutoMarginNombreSize = new JTextField("3.0");
    jTextAutoMarginNombreSize.setToolTipText("ノンブルの文字部分の高さを指定します。これより大きい場合はノンブル除去されません");
    jTextAutoMarginNombreSize.setHorizontalAlignment(JTextField.RIGHT);
    jTextAutoMarginNombreSize.setInputVerifier(new FloatInputVerifier(3.0f, 0.5f, 10));
    jTextAutoMarginNombreSize.setMaximumSize(text3);
    jTextAutoMarginNombreSize.setPreferredSize(text3);
    jTextAutoMarginNombreSize.setEditable(jCheckAutoMargin.isSelected());
    jTextAutoMarginNombreSize.addFocusListener(new TextSelectFocusListener(jTextAutoMarginPadding));
    panel.add(jTextAutoMarginNombreSize);
    label = new JLabel("% )");
    label.setBorder(padding2H);
    panel.add(label);

ChatGPT:

このSwingベースのUIコードをAndroidのPreferenceScreen(設定画面)に変換するには、以下のようにXMLとKotlin/Javaのコードを組み合わせて実装します。

Swing UI Android Preference
JCheckBox SwitchPreferenceCompat
JTextField EditTextPreference
JComboBox ListPreference
JPanel PreferenceCategoryまたはPreferenceScreen
setEditable() setEnabled()
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory android:title="余白除去">

        <SwitchPreferenceCompat
            android:key="auto_margin_enabled"
            android:title="有効"
            android:defaultValue="false" />

        <EditTextPreference
            android:key="auto_margin_limit_h"
            android:title="横方向の余白除去量"
            android:dialogTitle="横方向の余白除去量 (%)"
            android:defaultValue="15"
            android:enabled="false"
            android:inputType="number" />

        <EditTextPreference
            android:key="auto_margin_limit_v"
            android:title="縦方向の余白除去量"
            android:dialogTitle="縦方向の余白除去量 (%)"
            android:defaultValue="15"
            android:enabled="false"
            android:inputType="number" />

        <EditTextPreference
            android:key="auto_margin_padding"
            android:title="余白追加量"
            android:dialogTitle="余白追加量 (%)"
            android:defaultValue="1.0"
            android:enabled="false"
            android:inputType="numberDecimal" />

        <EditTextPreference
            android:key="auto_margin_white_level"
            android:title="白レベル"
            android:dialogTitle="白レベル (0〜100)"
            android:defaultValue="80"
            android:enabled="false"
            android:inputType="number" />

        <ListPreference
            android:key="auto_margin_nombre_position"
            android:title="ノンブル除去位置"
            android:defaultValue="なし"
            android:entries="@array/nombre_position_entries"
            android:entryValues="@array/nombre_position_values" />

        <EditTextPreference
            android:key="auto_margin_nombre_size"
            android:title="ノンブル高さ"
            android:dialogTitle="ノンブル高さ (%)"
            android:defaultValue="3.0"
            android:enabled="false"
            android:inputType="numberDecimal" />

    </PreferenceCategory>
</PreferenceScreen>
<resources>
    <string-array name="nombre_position_entries">
        <item>なし</item>
        <item>上</item>
        <item>下</item>
        <item>上下</item>
    </string-array>
    <string-array name="nombre_position_values">
        <item>none</item>
        <item>top</item>
        <item>bottom</item>
        <item>both</item>
    </string-array>
</resources>
class AutoMarginPreferenceFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences_auto_margin, rootKey)

        val enabledSwitch = findPreference<SwitchPreferenceCompat>("auto_margin_enabled")
        val dependentKeys = listOf(
            "auto_margin_limit_h",
            "auto_margin_limit_v",
            "auto_margin_padding",
            "auto_margin_white_level",
            "auto_margin_nombre_size"
        )

        val updateDependentPrefs: (Boolean) -> Unit = { isEnabled ->
            dependentKeys.forEach { key ->
                findPreference<Preference>(key)?.isEnabled = isEnabled
            }
        }

        enabledSwitch?.setOnPreferenceChangeListener { _, newValue ->
            updateDependentPrefs(newValue as Boolean)
            true
        }

        // 初期状態の反映
        enabledSwitch?.isChecked?.let { updateDependentPrefs(it) }
    }
}

これで、Swingの「余白除去」UIがAndroidのPreference画面に変換されます。必要であれば、より詳細なバリデーション(0〜100制限など)や単位の表示も追加可能です。

要望があれば、単位表示を含んだカスタムViewの作成例などもお手伝いできますよ!

あなた:

javaで書いて

ChatGPT:

了解しました! 下記は、Swingの「余白除去」設定UIを AndroidのJavaベースのPreferenceFragmentCompat で実装した例です。Kotlinではなく、Javaで書き直しています。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">

    <PreferenceCategory android:title="余白除去">

        <SwitchPreferenceCompat
            android:key="auto_margin_enabled"
            android:title="有効"
            android:defaultValue="false" />

        <EditTextPreference
            android:key="auto_margin_limit_h"
            android:title="横方向の余白除去量 (%)"
            android:defaultValue="15"
            android:enabled="false"
            android:inputType="number" />

        <EditTextPreference
            android:key="auto_margin_limit_v"
            android:title="縦方向の余白除去量 (%)"
            android:defaultValue="15"
            android:enabled="false"
            android:inputType="number" />

        <EditTextPreference
            android:key="auto_margin_padding"
            android:title="余白追加量 (%)"
            android:defaultValue="1.0"
            android:enabled="false"
            android:inputType="numberDecimal" />

        <EditTextPreference
            android:key="auto_margin_white_level"
            android:title="白レベル (0〜100)"
            android:defaultValue="80"
            android:enabled="false"
            android:inputType="number" />

        <ListPreference
            android:key="auto_margin_nombre_position"
            android:title="ノンブル除去位置"
            android:defaultValue="none"
            android:entries="@array/nombre_position_entries"
            android:entryValues="@array/nombre_position_values" />

        <EditTextPreference
            android:key="auto_margin_nombre_size"
            android:title="ノンブル高さ (%)"
            android:defaultValue="3.0"
            android:enabled="false"
            android:inputType="numberDecimal" />

    </PreferenceCategory>

</PreferenceScreen>
<resources>
    <string-array name="nombre_position_entries">
        <item>なし</item>
        <item>上</item>
        <item>下</item>
        <item>上下</item>
    </string-array>
    <string-array name="nombre_position_values">
        <item>none</item>
        <item>top</item>
        <item>bottom</item>
        <item>both</item>
    </string-array>
</resources>
public class AutoMarginPreferenceFragment extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.preferences_auto_margin, rootKey);

        SwitchPreferenceCompat switchAutoMargin =
                findPreference("auto_margin_enabled");

        String[] dependentKeys = new String[]{
                "auto_margin_limit_h",
                "auto_margin_limit_v",
                "auto_margin_padding",
                "auto_margin_white_level",
                "auto_margin_nombre_size"
        };

        if (switchAutoMargin != null) {
            boolean isEnabled = switchAutoMargin.isChecked();
            updateDependents(dependentKeys, isEnabled);

            switchAutoMargin.setOnPreferenceChangeListener((preference, newValue) -> {
                updateDependents(dependentKeys, (Boolean) newValue);
                return true;
            });
        }
    }

    private void updateDependents(String[] keys, boolean enabled) {
        for (String key : keys) {
            Preference pref = findPreference(key);
            if (pref != null) {
                pref.setEnabled(enabled);
            }
        }
    }
}
<activity android:name=".SettingsActivity" />
public class SettingsActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportFragmentManager()
            .beginTransaction()
            .replace(android.R.id.content, new AutoMarginPreferenceFragment())
            .commit();
    }
}

これで、Swing UI の「余白除去」設定が Android の Preference 画面として Javaで完全に再現されます!

必要であれば、単位(%)の表示や入力制限ロジック(バリデーション)を追加するカスタムバージョンも用意できます。やってみますか?